您的位置:首页 > 其它

Binary Serialization and BinaryFormatter with WebServices

2004-09-19 09:54 666 查看
"The Semantic Web is not a separate Web but an extension of the current one, in which information is given well-defined meaning, better enabling computers and people to work in cooperation." -- Sir Tim Berners-Lee

Recently we have had some forum posts with questions that generally seem to revolve around the topic of "How do I serialize and send an image over a WebService" and "BinaryFormatter doesn't work - gives Assembly Version exception".

New Articles & Tips
ASP.NET 1.1 SQLCacheDependency With SQLite
Build a C# SQL Server Database Export Utility
SQL Server Reporting Services - Lessons Learned
Dr. Dotnetsky's Cool .NET Tips and Tricks # 18
.NET Compact Framework Save Signature To File
HOWTO: Register an Assembly in the GAC
.NET Framework 1.1 SP1 - Issues
Circular References / Memory Leaks /other baddies
Rsources Section Now Open for Testing!
.NET Compact Framework App.Config Workaround

Rather than launch into a repetitious tirade of post-answering, I thought it might be a good time to examine this with some carefully considered sample code. What I've done here is to create a simple WebService that has two methods -
1) GetImage - Accepts a string for the image fileName (assumes Server.MapPath), reads the image off the file system into a Byte array, and then sticks it into the public byte[] "myImage" property of a simple serializable class, "ImageClass". This class is sent in its entirety as the return type from the method.
2) GetImageBytes - This method does exactly what the first method does, except that it use the BinaryFormatter to serialize the ImageClass instance , and sends the resultant byte array to the caller.
There are significant advantages to first storing our image in a property of a class instance and serializing the entire class, not the least of which is that we can have additional information besides "just the image" getting serialized and sent over the wire.
The method details of these two WebMethods follow:

[WebMethod]
public byte[] GetImageBytes(string strImageName)
{
ImageClass ic=new ImageClass();
FileStream fs = new FileStream(Server.MapPath(strImageName),
FileMode.OpenOrCreate, FileAccess.Read);
Byte[] img=  new Byte[fs.Length ];
try
{
fs.Read(img, 0, Convert.ToInt32(fs.Length));
}
catch(Exception ex)
{
Debug.WriteLine(ex.Message+ex.StackTrace);
}
fs.Close();
ic.myImage=img;
BinaryFormatter bf = new BinaryFormatter();
MemoryStream ms = new MemoryStream();
bf.Serialize(ms,ic);
return ms.ToArray();
}

[WebMethod]
public ImageClass GetImage(string strImageName)
{
ImageClass ic=new ImageClass();
FileStream fs = new FileStream(Server.MapPath(strImageName),
FileMode.OpenOrCreate, FileAccess.Read);
Byte[] img=  new Byte[fs.Length ];
try
{
fs.Read(img, 0, Convert.ToInt32(fs.Length));
}
catch(Exception ex)
{
Debug.WriteLine(ex.Message+ex.StackTrace);
}
fs.Close();
ic.myImage=img;
return ic;
}
The ImageClass needs to be put into a separate class library project that is referenced from the WebService class (as well as by the caller). This is how we prevent BinaryFormatter "Assembly" errors, because when we attempt to deserialize the output of the Formatter, the Assembly name, version and cultureInfo will all match. If you attempt to put your ImageClass class into the actual WebService project, this is what will cause you unnecessary headaches. The same goes for interfaces with remoting - need to get that serializable "thing" into a separate class library. So now here is the code for the ImageClass:

using System;
using System.Reflection;
using System.Drawing;
namespace ImageClassAssy
{
[Serializable]
public class ImageClass
{
public byte[] myImage;
public ImageClass()
{
}
}
}

Now for our test harness, we will use a Windows Forms app that uses a WebReference to our service, and has two buttons - one to exercise each method. Here is the code for each button, respectively:

private void button1_Click(object sender, System.EventArgs e)
{
// GetImage Method
BinaryFormatterSvc.Service1 s= new BinaryFormatterSvc.Service1();
BinaryFormatterSvc.ImageClass icc=s.GetImage(this.textBox1.Text);
byte[] byt=icc.myImage;
MemoryStream ms = new MemoryStream(byt);
Bitmap b=(Bitmap) Image.FromStream(ms);
pictureBox1.Image=b;
}
private void button2_Click(object sender, System.EventArgs e)
{
//GetImageBytes (BinaryFormatter) method
BinaryFormatterSvc.Service1 s= new BinaryFormatterSvc.Service1();
byte[] byt=s.GetImageBytes(this.textBox1.Text);
MemoryStream ms = new MemoryStream(byt);
BinaryFormatter bf= new BinaryFormatter();
ImageClass ic=(ImageClass)bf.Deserialize(ms);
MemoryStream ms2 = new MemoryStream(ic.myImage);
Bitmap b=(Bitmap) Image.FromStream(ms2);
pictureBox1.Image=b;
}
The result of our method call, with my handy "Pete.jpg" image sitting on the server, would look like so:


And, just in case you missed my first point, let's not forget to add a reference to our ImageClass assembly in our Winforms app, so that our client will know how to and "into what" to deserialize the type it has received and get out the image property for display.
download the Visual Studio 2003 Solution that accompanies this article
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐