Raza Ali

Raza Ali I am Currently working as an Architect and a Consultant at a Microsoft partner company. I have broad technology interests but find myself more interested in ASP.Net and backend server techonlogies. This blog for me is a means to share whatever I come to learn. Hope you find something useful here.
E-mail me Send mail
MCTS

Recent comments

Recent posts

Files I've Posted

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2010

Sign in

Saving/Retrieving images from SQL Server for ASP.Net Website

by raza 8/5/2008 10:52:46 PM

For one of the projects I am working on these days, I had to provide image hosting from the database meaning the images will be stored in the the database when the user uploads them to my site and is fetched from the database on request. After looking around for hardly 15mins the solution was there. SQL Server's image type came to the rescue but I read in some article that MS was going to discontinue this type and only keep the varbinary for such purposes. While its available in SQL Server 2005, why not take advantage of it.

Let's say we have the following table structure which represents the different sites of an organization. Each site has its own logo and needs to be displayed on different pages of our site.

image

Let's first look at how to save the image in the database when it is uploaded from one of the pages in the website (in case its desktop application there is one less step here).

image

If this were a desktop application I would have probably written:

image

Let me explain the code here a little. The fuLogoImage is a FileUpload control and the code is simply checking if a file was uploaded through the control when the pages was submitted, using its HasFile property. If it was, then simply get the file as a byte[] and use ADO.Net to write this array to a Image column in the database. In my case here I have used a Typed Dataset, hence the "ta" before the Sites representing the TableAdapter for the Sites table. Notice I simply passed the byte[] without any additional work. You can also simply write a Insert command with the byte[] placed at the right column and ADO.Net will take care of the streaming to database.

Once the file is stored in the database in the LogoImage column, we can then start writing code to display it in our pages. Since the images are being generated dynamically for a given ID, we need a method to bypass the static URL requirement of the image tag. Luckily, there is such a trick and it is called a HTTP Handler. Everything you service in a web server is handled through an HTTP handler, including your aspx pages. If you go to IIS Manager and open the properties of any application, then open the configuration tab, you will see a window like this:

image

which shows the handler for each type of file the web server (IIS) will be dealing with. Basically, IIS itself does not know how to deal with a file so it passes on the handing responsibility to one of these programs depending on the extension. If I double click the aspx handler description, I see:

image

So, all http commands for the aspx file are being handled by the asp_isapi.dll extension. This extension is responsible for all the aspx page interpretation, session handling and other features that you like so much. Coming back to our topic, we need to write a handler just like that to generate images dynamically. For that we will use the ASP.Net generic http handler. If you go to your project and add new item, you will see:

image

Adding this will give you something like this:

image

The handler implements the IHttpHandler interface which has the capability to handle all the Http commands like Get and Post etc. I you would like session handing capabilities then you can also implement the IRequiresSessionState or IReadOnlySessionState interface. Now, the IHttpHandler contains a function called ProcessRequest where we need to implement our custom logic. I am passing the image ID as a query string parameter to the handler and the code looks like the following:

public void ProcessRequest (HttpContext context) 
    {
        byte[] image;
        
        context.Response.ContentType = "image/jpeg";

        decimal siteid = decimal.Parse(context.Request.QueryString["SiteID"]);

        if (siteid == -1)
            image = GetNoLogo(context);
        else
        {
            ECFormsTableAdapters.Lkp_SitesTableAdapter taSites = new ECFormsTableAdapters.Lkp_SitesTableAdapter();
            ECForms.Lkp_SitesDataTable dtSites = taSites.GetDataBySiteID(siteid);

            if (dtSites.Count == 0 || dtSites[0].LogoImage == null)
                image = GetNoLogo(context);
            else
                image = dtSites[0].LogoImage;
        }
        context.Response.BinaryWrite(image);
    }

Here I fetch the image from the database and then simply write it to the response stream using the proper content type description. In my example I have placed the limit that the image has to be a jpg, as visible from the content type header. The GetNoLogo function basically replaces the image with a default logo that is stored in the file system. The code looks something like this:

private byte[] GetNoLogo(HttpContext context)
    {
        byte[] imageNoLogo;
        string nologopath = context.Server.MapPath("images/nologo.jpg");
        
        lock (lockObject)
        {
            FileStream fs = new FileStream(nologopath, FileMode.Open,FileAccess.Read);
            imageNoLogo = new byte[fs.Length];
            fs.Read(imageNoLogo, 0, (int)fs.Length);
            fs.Close();
        }        
        return imageNoLogo;
    }

I have put a lock around the file access to prevent multiple threads from simultaneously opening the file. I should use some caching strategy here but for the moment it is good enough. Now to use it in the asp.net code I define a image tag anywhere in the html

<asp:Image ID="ImgLogo" runat="server" Height="52px" />

and make the src look like this through the code in Page_Load:

ImgLogo.ImageUrl = string.Format("ImageHandler.ashx?SiteID={0}", SelectedSite);

and that's it! When the browser renders this image it calls the associated url for image and at the web server this url is a handler that dynamically renders the image using the parameter. Create a site with dynamic images from the database now. Obvious advantages include:

- Single storage of all files.

- Centralized management

- Database searching and meta data storage facility for the images

- Centralized backup and recovery

Some disadvantages include:

- Performance hit

- Single point of failure

But then, the choice is yours. Depending on the situation you have to pick one over another.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , ,

ASP.Net | SQL Server

Generate PDF using SSRS

by raza 7/7/2008 11:40:09 AM

While looking for a method to programmatically generate PDF I came across the possibility of using SQL Server Reporting Services for the job. It actually has a number of possible rendering options, among them are "XML, NULL, CSV, IMAGE, PDF, HTML4.0, HTML3.2, MHTML, EXCEL, and HTMLOWC".

The problem with generating PDF is that there are two components to the document, the format and the data. The format part is the real pain that on has to deal with, date can then simply put in placeholders. SSRS simplifies this by allowing you to generate the PDF report by first creating the report, using some data from the database, in its own designer. Once the report is designed you can use the web services exposed by reporting services to save it any of those formats.

The SSRS web service can be found at http://server/reportserver/reportservice.asmx

After adding this service reference you will find the following nifty function for rendering the report in any format you like.

public Byte[] Render(
   string Report,
   string Format,
   string HistoryID,
   string DeviceInfo,
   [Namespace].ParameterValue[] Parameters,
   [Namespace].DataSourceCredentials[] Credentials,
   string ShowHideToggle,
   out string Encoding,
   out string MimeType,
   out [Namespace].ParameterValue[] ParametersUsed,
   out [Namespace].Warning[] Warnings
   out string[] StreamIds);
   Member of [Namespace].ReportingService

According to the documentation the parameters are defined as following:

Parameters
Report
The full path name of the report.
Format
The format in which to render the report. This argument maps to a rendering extension. Supported extensions are XML, NULL, CSV, IMAGE, PDF, HTML4.0, HTML3.2, MHTML, EXCEL, and HTMLOWC.
HistoryID
Optional. The unique identifier of a report history snapshot to render for the specified report. The identifier is based on the date and time the report history was created.
DeviceInfo
An XML string that contains the device-specific content that is required by the rendering extension specified in the Format parameter. For more information about device information settings for specific output formats, see Device Information Settings.
Parameters
Optional. An array of ParameterValue[] objects that represent the report-specific parameters.
Credentials
Optional. An array of DataSourceCredentials[] objects that contains the data source credentials.
ShowHideToggle
Optional. The Show/Hide toggle ID.
Encoding
[out] The encoding used when report server renders the contents of the report.
MimeType
[out] The MIME type of the rendered report.
ParametersUsed
[out] An array of ParameterValue[] objects representing the query parameters, if any, that are stored along with the report. This parameter returns a value only if the report being rendered is a report history snapshot.
Warnings
[out] An array of Warning[] objects that describes any warnings that occurred during report processing.
StreamIds
[out] The stream identifiers. These IDs are passed to the RenderStream method. You can use them to render the external resources (images, etc.) that are associated with a given report.
Return Value

A Byte[] array of the report in the specified format. For more information about this data type, see "Byte Structure" in the .NET Framework documentation.

The following piece of code may be used to generate a PDF of the report you created.

private void RenderTest_Click(object sender, System.EventArgs e)
        {
            RSWebReference.ReportingService rs = new RSWebReference.ReportingService(); 
            rs.Credentials = System.Net.CredentialCache.DefaultCredentials;

            Byte[] result; 

            string encoding;
            string mimetype;
            ParameterValue[] parametersUsed;
            Warning[] warnings;
            string[] streamids;

            result = rs.Render("/SampleReports/Company Sales","PDF",null,null,null,null,null,out encoding,out mimetype,out parametersUsed,out warnings,out streamids); 
                        
            Response.ClearContent();
            Response.AppendHeader("content-length", result.Length.ToString());
            Response.ContentType = "application/pdf";
            Response.BinaryWrite(result);
            Response.Flush();
            Response.Close();
        }

If the reporting service is not satisfying your requirements or you simply don't have reporting service available then you can use on of the following libraries to generate PDF through your own code: C# open-source PDF Libraries

Render Method on MSDN

PDF Generation KB

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: ,

.Net | SQL Server

Powered by BlogEngine.NET 1.4.0.0
Theme by Mads Kristensen