Explanation:
We already included some Articles about displaying Image
in ASP .NET. It was about displaying and saving an Image in MS SQL Database.
Saving an Image to Profile:
ALL
data types which are Serealizable can be saved in the Profile.
Serialization is the process of saving the state of an object by converting it to
a stream of bytes. The object can then be persisted to file, database, or even memory.
The reverse process of serialization is known as deserialization . (see the following
Figure)
Uses of serialization
Serialization is
used in many scenarios, but the main purpose is to save the state of an object in
order to have the ability to recreate the same object when required. It is an important
to let the user save work and then be able to continue from that point at a later
time. This is a common need in various tools and applications. Serialization is
also used in creating a clone of an object.
Another important need for serialization arises when the object is required to travel
electronically over wire. In such cases the objects are serialized and deserialized.
In fact, serialization is one of the fundamental requirements for techniques such
as .NET Remoting.
Even the hibernation mode in the Windows Operating system can be considered a form
of serialization.
Image serialization
S erialization
is an important entity of pipelining an Object from one point to other point. The
.NET Framework provides certain built-in mechanisms which can be used to serialize
and deserialize objects. This functionality can be found in the System.Runtime.Serialization. and the System.Xml.Serialization
namespaces of the .NET Framework
Here we will restrict our discussion to serialization of an Image. Image
is serialized as a binary data to the Database or a file.
In ASP .NET to show an Image from a location would be an easy target
as we can use simply “src” property of an Image control with pointing
it to the image file location and every thing will be fine. But harder efforts need
to perform when we want to show an image from Database.
Saving an image to a database is a different story also. It needs different
programming technique to store a binary data (Image) into a database rather then
saving it (Image) to a file location.
After long theoretical Introduction now we are able to describe the methods
to save/retrieve an Image to/from a Profile (as Profile is also saving data to a
Database).
The 1st step will be to tell the Web server/Database server
that you are adding a new field to the User Profile system. We will perform this
like the following:
<profileenabled="true"automaticSaveEnabled="false" >
<properties>
-----other properties come here------
<addname="Picture"
type="System.Drawing.Bitmap"
serializeAs="Binary"/>
</properties>
</profile>
You noticed that the Data type is a “Bitmap”.
Why not an Image? Image is an Abstract class which is meant to Inherit. This is
a base class that provides functionality for the
Bitmap and
Metafile descended classes.
Abstract classes are like Interfaces with the difference that methods
and properties of an abstract Class can contain different types of Accessor where
as an Interface does not contain any type of Accessor i.e. it is solely created
to implement.
There are some similarities and differences between an interface and
an abstract class that I have arranged in a table for easier comparison:
|
Feature
|
Interface
|
Abstract class
|
|
Multiple inheritance
|
A class may inherit several interfaces.
|
A class may inherit only one abstract class.
|
|
Default implementation
|
An interface cannot provide any code, just the signature.
|
An abstract class can provide complete, default code and/or just the
details that have to be overridden.
|
|
Constants
|
Only Static final constants.
|
Both instance and static constants are possible.
|
|
Core VS Peripheral
|
Interfaces are used to define the peripheral abilities of a class. In
other words both Human and Vehicle can inherit from a IMovable interface.
|
An abstract class defines the core identity of a class and there it is
used for objects of the same type.
|
|
Homogeneity
|
If the various implementations only share method signatures then it is
better to use Interface.
|
If the various implementations are of the same kind and use common behaviour
or status then abstract class is better to use.
|
|
Speed
|
Requires more time to find the actual method in the corresponding classes.
|
Fast
|
|
Adding functionality
|
If we add a new method to an Interface then we have to track down all
the implementations of the interface and define implementation for the new method.
|
If we add a new method to an abstract class then we have the option of
providing default implementation and therefore all the existing code might work
properly.
|
To save the Image in Profile would be more easy assignment then retrieving
from the Profile. See the following code for saving an Image:
ProfileCommon
prof = Profile.GetProfile("UserName");
prof.Picture = new System.Drawing.Bitmap(
Server.MapPath(@"ImageFolder\Logo-Stars.png"));
prof.Save();
We retrieved the user profile, created a new bitmap and then assigned
it to the Profile Field.
To Retrieve the Image we need to cerate a Binary stream. For this we
will use System.IO Namespace.
Now, the hard story starts. As we said that we will load an image using
a stream. Normally, we can do this by cerating a Method which return type is a stream.
In ASP .NET its not easy to display image as <image> tage
loads an Image using src attribute. This only allows a file or
a web page path to load an Image. So what is the solution? Yes there is a solution.
In ASP .NET we use a handler for this reason.
What is a Handler?
A handler is responsible for fulfilling requests from a browser. Requests
that a browser manages are either handled by file extension (or lack thereof) or
by calling the handler directly. Only one handler can be called per request. A handler
does not have any HTML static text like .aspx or .ascx files. A handler is a class
that implements the IHttpHandler interface. If you need to interact with any Session
information, you will also need to implement IRequiresSessionState. If you want
to make an asynchronus handler, you will need to implement the IHttpAsyncHandler
interface instead of the IHttpHandler interface.
Calling a Handler by File Extension
A handler can be invoked by any file extension that is mapped via the
web.config and the IIS file extension mappings. You can have a file named something.billybob
where 'billybob' is the file extension, or you can have no file extension at all
such as http://web/handler/file where a request for 'file' without an extension
invokes a handler mapped to *.* or the directory as *.
Calling a Handler Directory
The code file for the handler has the file extension of 'ashx' on the
web server. This file can be called directly via a browser without having to set
up web.config or IIS file extension mappings. For example: http://web/handler/handler.ashx.
Some examples of this hander type are photo albums, RSS feeds, and blogging
sites. Each of these is a good example of work that can be better accomplished without
standard HTML. A photo album involves directory crawling and responding with pictures.
A RSS feed returns information in the correct format.
If you cerate a Handler with visual studio it will look like this:
<%@ WebHandler Language="C#" Class="Handler" %>
using System;
using System.Web;
public class Handler : IHttpHandler {
public void ProcessRequest (HttpContext context) {
context.Response.ContentType = "text/plain";
context.Response.Write("Hello
World");
}
public bool IsReusable {
get {
return false;
}
}
}
By browsing this Handler we will get a Text "Hello World" in
our page. If you noticed that we always have to copy our data to the Context.
Data can wrote to context either as a Text or as a
Binary data.
When we want to copy a simple text to the Context we use Response.Write()
method but how to Copy a Binary data? As we discribed earlier Image is a binary
data (in GDI Langauge it’s a Two dimesional Array of Pixels. Don’t mix
these two defination as both are ture i.e. Two dimensional data is saved in binary
Format). We use Response.OutputStream.Write () to write a Binary
data to the Context.
There is a little different senario in Plan C# Application (GDI, GDI+)
that we use the Bitmap.Save() method instead for saving the Binary
data to out put stream. So don’t get confuse in here because in Web page development
our stream needs to Serialized to the Client Context that’s why we use
Response.OutputStream.Write ().
I guess this was kind of simple to undertsand the difference. Now the
question comes which Overload method we can use to write an Image to the Outputstream
of the Context? We will use the method which takes Byt array of the Binary Data.
Now see how dows our code look like this:
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "image/jpeg";
context.Response.Cache.SetCacheability(HttpCacheability.Public);
ProfileCommon prof = new ProfileCommon();
ProfileCommon prof2 = prof.GetProfile(context.Request.QueryString["UserName"]);
Bitmap myBitmap = prof2.Picture;
byte[] b = GetImageBytes(myBitmap);
context.Response.OutputStream.Write(b, 0,
b.Length);
}
We created a Profile Object then used its method to fill the other object,
with the User Profile Data. We can not do this in one line because we need a Profile
Object before we can use its method GetProfile(). As in Handler
Context we can not access the Page Methods. Where context.Request.QueryString["UserName"]
is used to access the Qureystring member “UserName” (we will account
this later when we pass a member to the Handler).
What if we want to access an image from a File location? In this senario
we need a Page Object as it contains the Server.Map()
method. This will look like the following:
Page
pg = new Page();
Bitmap
myBitmap = new Bitmap(pg.Server.MapPath(@"ImageFolder\Logo-Stars.png"));
Now see how to convert the Bitmap to a byte Array.
private byte[] GetImageBytes(Image image)
{
ImageCodecInfo
codec = null;
foreach (ImageCodecInfo
e in ImageCodecInfo.GetImageEncoders())
{
if (e.MimeType == "image/png")<
{
codec = e;
break;
}
}
using (EncoderParameters
ep = new EncoderParameters())
{
ep.Param[0] = new EncoderParameter(Encoder.Quality, 100L);
using (MemoryStream ms = new MemoryStream())
{
image.Save(ms, codec, ep);
return ms.ToArray();
}
}
}
This is actually the main trick. If you try to save the Image stream
in a Stream format to the outputstream it will simply not work because Data is Transferred/Transmited
in the Bytes format. So we have to convert the Stream in Bytes first before sending
it int to the Pipeline.
Now the last point comes how to assign the Handler to
a <Img> Tage? Its very simple:
<img runat="server" id="image" src="ProfilePicHandler.ashx?UserName=SomeName"
alt="Profile Image"
/>
Here we are passing a Qureystring member “UserName” to the
Handler. Values after “?” come in the account of Querystring and it
can be accessed at the Distination Page. Here Mamber Name is “UserName”
and its value is “SomeName”.
If you are planing to make a Dynamic generation users profile images
then you can use code behind instead. But, you have to get the UserName from any
source. The source could be a Membership and MembershipUser
Objects.
public
void uploadUserPictures()
{
MembershipUserCollection users
= Membership.GetAllUsers();
foreach
(MembershipUser user in users)
{
image.sr
= "ProfilePicHandler.ashx?UserName="+user.UserName;
}
}
So our whole code of the Handler will look like this:
<%@ WebHandler
Language="C#"
Class="ProfilePicHandler"
%>
using System;
using System.Web;
using System.Web.Profile;
using System.Web.Security;
using System.IO;
using System.Web.UI;
using System.Drawing;
using System.Drawing.Imaging;
public class ProfilepicHandler : IHttpHandler {
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType
= "image/jpeg";
context.Response.Cache.SetCacheability(HttpCacheability.Public);
ProfileCommon
prof = new ProfileCommon();
ProfileCommon
prof2
= prof.GetProfile(context.Request.QueryString["UserName"]);
Bitmap myBitmap
= prof2.Picture;
byte[] b =
GetImageBytes(myBitmap);
context.Response.OutputStream.Write(b,
0, b.Length);
}
public bool IsReusable {
get {
return false;
}
}
private byte[] GetImageBytes(Image
image)
{
ImageCodecInfo
codec = null;
foreach (ImageCodecInfo
e in ImageCodecInfo.GetImageEncoders())
{
if (e.MimeType == "image/png")
{
codec = e;
break;
}
}
using (EncoderParameters
ep = new EncoderParameters())
{
ep.Param[0] = new EncoderParameter(Encoder.Quality, 100L);
using (MemoryStream ms = new MemoryStream())
{
image.Save(ms, codec, ep);
return ms.ToArray();
}
}
}
}
Hope it Help.
|