asp tutorials, asp.net tutorials, sample code, and Microsoft news from 15Seconds
Data Access  |   Troubleshooting  |   Security  |   Performance  |   ADSI  |   Upload  |   Email  |   Control Building  |   Component Building  |   Forms  |   XML  |   Web Services  |   ASP.NET  |   .NET Features  |   .NET 2.0  |   App Development  |   App Architecture  |   IIS  |   Wireless
 
Pioneering Active Server
 Power Search








Active News
15 Seconds Weekly Newsletter
• Complete Coverage
• Site Updates
• Upcoming Features

More Free Newsletters
Reference
News
Articles
Archive
Writers
Code Samples
Components
Tools
FAQ
Feedback
Books
Links
DL Archives
Community
Messageboard
List Servers
Mailing List
WebHosts
Consultants
Tech Jobs
15 Seconds
Home
Site Map
Press
Legal
Privacy Policy
internet.commerce














internet.com
IT
Developer
Internet News
Small Business
Personal Technology
International

Search internet.com
Advertise
Corporate Info
Newsletters
Tech Jobs
E-mail Offers

HardwareCentral
Compare products, prices, and stores at Hardware Central!

Implementing DIME – Creating a Document Sharing System
By Robert Chartier
Rating: 4.4 out of 5
Rate this article


  • email this article to a colleague
  • suggest an article

    Introduction

    Web Services has led to so many new, emerging standards, it's difficult to track them all. With this in mind, I decided to more closely examine the DIME specification, and specifically the tools Microsoft offers to handle Direct Internet Message Encapsulation (DIME) within .NET.

    When we hear "DIME," we need only to think about attachments. The client and the server are sending messages back and forth, and documents can be optionally attached to these messages. For example, an organization may have a Web Service that enables you to send it postal zip code and it will return a series of maps about that location. DIME could provide a flexible method for transmitting the binary map data.

    Currently binary data can be sent and received within a normal Web Service in .NET Framework simply by using the byte[] data type on messages. The framework will automatically base64 (http://www.topxml.com/xml/articles/binary/) encode and decode this data over the wire. Here is an example of this on the server:

    
    [WebService(Namespace="http://rob.santra.com/webservices/public/images/", 
    Description="Demonstration of using Base64 encoding, in a Web Service using the 
    .NET Framework.")]
    	public class Images: System.Web.Services.WebService {
    
    	[WebMethod(Description="Get an Image using Base64 Encoding")]
    	public byte[] GetImage() {
    		return GetImageAsBytes();  //simplified example
    	}
    
    
    Full service code can be found at http://www.aspalliance.com/nothingmn/default.aspx?whichpoll=nothingmn_121&aid=121.

    The GetImage method has a return type of byte[]. It takes the image, say a GIF or JPEG, and converts it (packs it using base64 encoding) into a format that we can send over Web Services within eXtensible Markup Language (XML). This takes the entire data into a single buffer while a message is created for the client. With DIME, however, chunks of data can be sent down the wire instead of buffering the entire message. This has obvious advantages because the server can quickly respond with the message and allow for the client to start processing the binary message while the server is still sending data. For example, there may be a large database query. As the server produces results, it can just keep sending it to the client, and the client can receive and take action based on that.

    Requirements

    To fully understand this article, a basic understanding of Web Services and how to create and consume them within the Microsoft .NET Framework is required. Visual Studio .NET (http://msdn.microsoft.com/vstudio/default.asp) needs to be installed with the Web Services Enhancements for .NET (http://msdn.microsoft.com/webservices/building/wse/default.aspx).

    Lastly, at least skim over the excellent introduction to the DIME specification at http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnservice/html/service01152002.asp. Just get an overview of what DIME is, pay attention to the fact that it is a specification for sending and receiving document attachments, understand how it differs from Multipurpose Internet Mail Extensions (MIME), and recognize the size limitations of this protocol. Don't bother memorizing the exact details, like the DIME headers, or what the bit-by-bit message headers would look like, but gain an overview of how and why this specification was created.

    Download source code for this article

    Application Overview

    This article focuses on the implementation of a simple application that uses DIME technology. I create a tool similar to the File Transfer Protocol (FTP) (since most of us understand what FTP does), but apply DIME to the actual transferring of the documents.

    The application allows for an administrator to publish documents and folders. It has a Web Services interface that uses Simple Object Access Protocol (SOAP) headers for authentication and DIME when sending and receiving the documents. For this demonstration I used SQL Server for storing the user credentials and for keeping track of which folders are exposed on our Web Service.

    Users provide the application with their credentials (a username and password) and an end point for the Web Service. Our client code will connect to this Web Service, and if the credentials are acceptable (valid username and password), the Web Service will return a list of the available folders or an error.

    Next, the client can browse the folders and get a list of files in each. Once they have chosen a file, they can download it, edit it, and then optionally upload it back to the server.

    As you can see this is very similar to FTP. It is not my intention to replace FTP, but to merely demonstrate how you would create an application using DIME and Web Services in a fashion that you are familiar with. Most can relate to the functionality of the FTP process.

    The Server

    Authentication

    For this application, SOAP headers send and receive authentication information. Here is a look at our header class.

    
    using System;
    
    namespace IDSSServer {
    	public class AuthHeader : System.Web.Services.Protocols.SoapHeader {
    		protected string username;
    		protected string password;
    		protected string guid;
    		protected System.DateTime sessionStarted;
    		protected IDSSServer.User user;
    		public AuthHeader(){}
    		public AuthHeader(string Username, string Password) {
    			username=Username;
    			password=Password;
    			user = new IDSSServer.User(Username, Password);
    		}
    		public AuthHeader(string Guid) {
    			guid=Guid;
    		}
    		public string Username{get{return username;}set{username=value;}}
    		public string Password{get{return password;}set{password=value;}}
    		public string Guid{get{return guid;}set{guid=guid;}}
    		public System.DateTime SessionStarted{get{return 
    sessionStarted;}set{sessionStarted=sessionStarted;}}
    	}
    }
    
    
    Recognize how this class creates an instance of the IDSSServer.User() class. This user class is where the actual authentication occurs. This is an example of how to tie this system into an existing user authentication infrastructure in an existing application. The user class follows:
    
    using System;
    
    namespace IDSSServer {
    	[System.Serializable()]
    	public class User {
    		protected string username="";
    		protected string password="";
    		protected string guid="";
    		protected System.DateTime sessionStarted=System.DateTime.MinValue;
    		public User(string Username, string Password) {
    			username=Username;
    			password=Password;
    		}
    		public User(string Username, string Password, string Guid) {
    			username=Username;
    			password=Password;
    			guid=Guid;
    		}
    		public User(string Guid) {
    			guid=Guid;
    		}
    		public bool Login() {
    			IDSSServer.DAL dal = new IDSSServer.DAL();
    			string[] userdata = dal.GetUserData(username, password, guid);
    			if(userdata!=null) {
    				this.username=Convert.ToString(userdata[0]);
    				this.password=Convert.ToString(userdata[1]);
    				this.guid=Convert.ToString(userdata[2]);
    				this.sessionStarted=Convert.ToDateTime(userdata[3]);
    				return true;
    			} else {
    				this.username=null;
    				this.password=null;
    				this.guid=null;
    				this.sessionStarted=System.DateTime.MinValue;
    				return false;
    			}
    		}
    		public string Username{get{return username;}set{if(value!=null)username=value;}}
    		public string Password{get{return password;}set{if(value!=null)password=value;}}
    		public string Guid{get{return guid;}set{if(value!=null)guid=value;}}
    		public System.DateTime SessionStarted{get{return 
    sessionStarted;}set{if(value!=System.DateTime.MinValue)sessionStarted=value;}}
    	}
    }
    
    
    Here you can see that the Login() method creates and calls an instance of our data access layer (DAL), the IDSSServer.DAL() class. This DAL is responsible for performing the interaction with our data store. It's useful to create a single entry point to our data store, whether it's a Microsoft Access database, XML document, SQL Server database, or even the file system. In this case, the DAL will provide an interface into SQL Server and our file system. This offers a single point of change if you ever need to modify the location of your data.

    For example, I could have created this application by simply using an XML data store for the user data and folder listings, and then upgraded the entire application so it used SQL Server exclusively. In this case I would only need to change this DAL class, and nothing else in the application would be effected or require change. This will prove important when we need to grow our system to meet the demands of our client base. Here is the user authentication portion of our DAL:

    
    namespace IDSSServer {
    	public class DAL {
    		protected System.Data.SqlClient.SqlConnection conn;
    		protected int sessionTimeout=10;  //in minutes
    		protected string 
    constring=System.Configuration.ConfigurationSettings.AppSettings["IDSSConnection
    "];
    		public DAL() {
    		}
    		public string[] GetUserData(string Username, string Password, string 
    Guid) {
    			if(Guid==null) Guid="";
    			if(Username==null) Username="";
    			if(Password==null) Password="";
    
    			string[] userdata=null;
    			Connect();
    			System.Data.SqlClient.SqlCommand cmd = conn.CreateCommand();
    			cmd.CommandText="PerformLogin";
    			cmd.CommandType=System.Data.CommandType.StoredProcedure;
    			cmd.Parameters.Add("@username", Username);
    			cmd.Parameters.Add("@password", Password);
    			cmd.Parameters.Add("@guid", Guid);
    			cmd.Parameters.Add("@timeout", sessionTimeout);
    			System.Data.SqlClient.SqlDataReader userRdr = 
    cmd.ExecuteReader();
    			if(!userRdr.IsClosed) {
    				userRdr.Read();
    				if(userRdr.GetValue(0)!=System.DBNull.Value && 
    userRdr.GetValue(0)!=null) 
    		userdata = new string[]{Convert.ToString(userRdr.GetValue(0)), 
    Convert.ToString(userRdr.GetValue(1)), Convert.ToString(userRdr.GetValue(2)), 
    Convert.ToString(userRdr.GetValue(3)) };
    			}
    			userRdr=null;
    			Disconnect();
    			return userdata;
    		}
    }
    
    
    It is simply calling out to SQL Server to ensure that the username and password or Globally Unique IDentifier (GUID) are valid. If the GUID is not valid, but the username and password are, it will assign a new GUID to be used. Otherwise it will not produce a valid GUID, and the login will be invalid.

    The next step is the stored procedure "PerformLogin." Since this is fairly basic and not specifically related to this article, it will not be explained.

    Folder Listing

    Once we have a valid user, we need to get a list of the folders the user may access. A database is used to list the folder and control access to each folder. The stored procedure "GetFolders" and look at the two tables, "Folders" and "UserFolders." What I have done here is self-explanatory.

    The ability to generate a list of folders must now be implemented by our Web Service. In the DAL, our direct connection to the database, is a method that will query the database, using the "GetFolders" stored procedure, for a list of folders:

    
    public System.Collections.ArrayList GetUserFolders(IDSSServer.User user) {
    	System.Collections.ArrayList folders=null;
    	Connect();
    	System.Data.SqlClient.SqlCommand cmd = conn.CreateCommand();
    	cmd.CommandText="GetFolders";
    	cmd.CommandType=System.Data.CommandType.StoredProcedure;
    	cmd.Parameters.Add("@guid", user.Guid);
    	System.Data.SqlClient.SqlDataReader fldrRdr = cmd.ExecuteReader();
    	
    	if(!fldrRdr.IsClosed) {
    		folders = new System.Collections.ArrayList();
    		while(fldrRdr.Read()) {
    			IDSSServer.Folder flder = new IDSSServer.Folder();
    			flder.Fullpath=fldrRdr.GetString(0);
    			flder.Name=fldrRdr.GetString(2);
    			flder.Write=(Convert.ToString(fldrRdr.GetValue(1))=="1")?true:false;
    			folders.Add(flder);
    		}
    	}
    	fldrRdr=null;
    	Disconnect();
    	return folders;
    }
    
    
    Within the while loop we are creating an instance of a Folder object. I created this class to handle the description of exactly what a folder is, which makes it easier for the client and the server to deal with a folder when they are communicating with each other. Our method above will gather a list of these folder objects and return them back to our Web Service. Here is the Folder class:
    
    using System;
    
    namespace IDSSServer {
    	[System.Serializable()]
    	public class Folder {
    		protected string name;
    		protected string fullpath;
    		protected bool write;
    
    		public Folder() {
    		}
    		public Folder(string Path) {
    		}
    		public string Name{get{return name;}set{name=value;}}
    		public string Fullpath{get{return fullpath;}set{fullpath=value;}}
    		public bool Write{get{return write;}set{write=value;}}
    
    	}
    }
    
    
    We have a collection of folders, but let's back up and look at the actual Web Service. The Web Service simply exposes a method that allows the user to use the authentication features described above and to retrieve a list of the folders. Here is the relevant portion of the service:
    
    public IDSSServer.AuthHeader authHeader;
    [WebMethod]
    [System.Web.Services.Protocols.SoapHeader("authHeader", 
    Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut,Required=true)]
    public IDSSServer.Folder[] GetFolderList() {
    	IDSSServer.Folder[] folders=null;
    	IDSSServer.User user = new IDSSServer.User(authHeader.Username, 
    authHeader.Password, authHeader.Guid);
    	if(user.Login()) {
    		//valid login
    		IDSSServer.DAL dal = new IDSSServer.DAL();
    		System.Collections.ArrayList flds = dal.GetUserFolders(user);
    		folders = new IDSSServer.Folder[flds.Count];
    		int x =0;
    		foreach(IDSSServer.Folder folder in flds) {
    			folders[x]=folder;
    			x++;
    		}
    	} else {
    		throw new System.Web.Services.Protocols.SoapException("Invalid 
    Login", new System.Xml.XmlQualifiedName("AuthHeader"));
    	}
    	return folders;
    }
    
    
    
    We are implementing our authentication header class by first creating a local instance of the "AuthHeader()" class. Then we are adding the "SoapHeader()" attribute on our GetFolderList() member, with the first parameter being the name of our local instance of our class. This process should be familiar to you, and if not, review http://www.aspalliance.com/nothingmn/default.aspx?aid=123. Now that we have the header class, we need to use it, and that's what we are doing here:
    
    IDSSServer.User user = new IDSSServer.User(authHeader.Username, 
    authHeader.Password, authHeader.Guid);
    	if(user.Login()) {
    
    
    The User class is loaded with the relevant authentication information received from the Web Service client. The user attempts to log in based on that data. If this fails, we gracefully throw back the SoapException, which the client is in charge of dealing with. The SoapException is the exception that is thrown when an XML Web service method is called over SOAP and an exception occurs. If the authentication details are valid, we can then connect to our DAL, grab our folders, and send the folders back out to the calling Web Service client. In the future, recognize how each request to the server will go through the same few basic lines of authentication, so I will not cover this again.

    Retrieving a List of Files

    Once the end user has a list of folders, a list of the files within each folder can be requested. In the Web Service and the DAL we need to provide the necessary methods to perform these operations. In our Web Service there is:

    
    [WebMethod]
    [System.Web.Services.Protocols.SoapHeader("authHeader", 
    Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut,Required=true)]
    public string[] GetFileList(string fullpath) {
    	IDSSServer.User user = new IDSSServer.User(authHeader.Username, 
    authHeader.Password, authHeader.Guid);
    	if(user.Login()) {
    		//valid login
    		return DAL.GetFiles(user, fullpath);
    	} else {
    		throw new System.Web.Services.Protocols.SoapException("Invalid 
    Login", new System.Xml.XmlQualifiedName("AuthHeader"));
    	}
    }
    
    
    This method allows the user to request a list of files based on a given path. Within the application, the path is provided. In the DAL, this is simply calling the GetFiles() method within the System.IO.Directory class.
    
    public static string[] GetFiles(IDSSServer.User user, string FullPath) {
    	return System.IO.Directory.GetFiles(FullPath);
    }
    
    
    Retrieving a File

    The user needs to be able to grab the file from the server and download it to the client. This is where DIME affects our application. Our method makes a call to the DAL to request the Microsoft.Web.Services.Dime.DimeAttachment that will represent the requested file.

    
    [WebMethod]
    [System.Web.Services.Protocols.SoapHeader("authHeader", 
    Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut,Required=true)]
    public void GetFile(string fullpath) {
    	IDSSServer.User user = new IDSSServer.User(authHeader.Username, 
    authHeader.Password, authHeader.Guid);
    	if(user.Login()) {
    		//valid login
    		Microsoft.Web.Services.Dime.DimeAttachment attach = 
    DAL.GetFile(user, fullpath);
    		Microsoft.Web.Services.HttpSoapContext.ResponseContext.Attachments.Add(att
    ach);
    	} else {
    		throw new System.Web.Services.Protocols.SoapException("Invalid 
    Login", new System.Xml.XmlQualifiedName("AuthHeader"));
    	}
    }
    
    
    Within the DAL, we can take a file stream and plug that directly into our Microsoft.Web.Service.Dime.DimeAttachment object. Using DIME on the server is an extremely easy process.
    
    public static Microsoft.Web.Services.Dime.DimeAttachment GetFile(IDSSServer.User 
    user, string FullPath) {			
    	System.IO.FileStream stream = System.IO.File.OpenRead(FullPath);
    	Microsoft.Web.Services.Dime.DimeAttachment attach = new 
    Microsoft.Web.Services.Dime.DimeAttachment("0", 
    Microsoft.Web.Services.Dime.TypeFormatEnum.MediaType, stream);
    	//attach.Type="text/plain";
    	return attach;			
    }
    
    
    If necessary, we could also permit the user to request more than one file, and all we would have to do is load up the DimeAttachment and add it to our Attachments collection.

    Uploading a File

    On the server side of this application, we will want to take an attachment sent by the client and save it back to disk. The member that we have for this also uses the DimeAttachment class to communicate with and accept the document. In our implementation, the Web Service code simply takes the file and calls upon our DAL to save the attachment to disk:

    
    [WebMethod]
    [System.Web.Services.Protocols.SoapHeader("authHeader", 
    Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut,Required=true)]
    public bool SaveFile(string FullPath) {
    	IDSSServer.User user = new IDSSServer.User(authHeader.Username, 
    authHeader.Password, authHeader.Guid);
    	if(user.Login()) {
    		//valid login
    		return IDSSServer.DAL.SaveFile(FullPath, 
    Microsoft.Web.Services.HttpSoapContext.RequestContext.Attachments[0].Stream);
    	} else {
    		throw new System.Web.Services.Protocols.SoapException("Invalid 
    Login", new System.Xml.XmlQualifiedName("AuthHeader"));
    	}
    }
    
    
    The DAL's SaveFile method follows:
    
    public static bool SaveFile(string path, System.IO.Stream contents) {
    	byte[] data = ConvertStreamToByteBuffer( contents );
    	if(System.IO.File.Exists(path)) System.IO.File.Delete(path);
    	System.IO.FileStream outfile = System.IO.File.OpenWrite(path);
    	outfile.Write(data, 0, data.Length);
    	outfile.Close();				
    	return (System.IO.File.Exists(path));
    }
    
    
    Given the complexity of Web Services and DIME, appreciate how much work Microsoft put into the Web Services Enhancements (WSE) technology in order to simplify things for us. In fact, most of us could easily implement this with little knowledge of the underlying protocols and specifications. This is typical of the .NET Framework as a whole.

    ASP.NET and WSE

    Add a new section within the Web.config file, under the system.web section. This registers a new extension on the server, which the Microsoft.Web.Services implementation requires in order to work properly within the ASP.NET environment.

    
    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <system.web>
        <webServices>
          <soapExtensionTypes>
    	  <add type="Microsoft.Web.Services.WebServicesExtension,Microsoft.Web.Services,Version
    =1.0.0.0, Culture=neutral,PublicKeyToken=31bf3856ad364e35" priority="1" 
    group="0"/>
    	</soapExtensionTypes>
        </webServices> 
      </system.web>
    </configuration>
    
    
    It is an easy thing to forget, so make sure you remember to add this! This allows that the WSE filters have a chance to process the incoming and outgoing SOAP messages. For more information, see "Integration with ASP.NET Web Services" at http://msdn.microsoft.com/webservices/default.aspx?pull=/library/en-us/dnwebsrv/html/progwse.asp.

    The Client

    Specifying the Connection

    To this point, the article has addressed the server implementation, and it'll now examine the client. We will need to generate a proxy client for our Web Service. This can be done in the manner described previously. Either use the Web Services Description Language (WSDL) wsdl.exe command-line utility or select the Web Reference menu item within VS.NET. Also, take a closer look at the WSE Settings tool. The WSE Settings tool is used to manage the WSE application settings from within VS.NET. Download it at http://msdn.microsoft.com/downloads/default.asp?url=/downloads/sample.asp?url=/MSDN-FILES/027/002/108/msdncompositedoc.xml.

    I suggest downloading the source code and samples provided in the download package now. Run the application, and play with it on your own server. This will clarify things for the rest of this article.

    The first thing we must do on the client is allow the user to provide his/her username and password credentials. A simple Connect form is provided for this purpose.

    Let's drill down and see what the "Connect..." button is doing.

    
    private void connectButton_Click(object sender, System.EventArgs e) {
    	if(localPathTextBox.Text.Substring(localPathTextBox.Text.Length-
    1,1)=="\\") localPathTextBox.Text = localPathTextBox.Text.Substring(0, 
    localPathTextBox.Text.Length-1);
    	if(!System.IO.Directory.Exists(localPathTextBox.Text)) {
    		System.IO.Directory.CreateDirectory(localPathTextBox.Text);
    	}
    	statusBar1.Text="Attempting Connect...";
    	connection = new IDSSClientLibrary.Connection(serverTextBox.Text, 
    usernameTextBox.Text, passwordTextBox.Text);			
    	connection.LocalPath=localPathTextBox.Text;
    	if(connection.Connect()) {
    		statusBar1.Text="Connected!";
    		this.Text="Connected";				
    	} else {
    		statusBar1.Text="Connection Failed!";
    		this.Text="Connection Failed";				
    	}
    	this.Hide();
    	this.Close();
    }
    
    
    First, recognize that it validates the local path. This local path is a temporary cache folder used when files and folders are downloaded off our service. Next it creates an IDSSClientLibrary.Connection() object. This object's primary task is to perform all of the work with our Web Service via the proxy. It allows us to have a single interface to handle all of the communication with the Web Service. Lastly it attempts to call the Connect() method in our Connection() object. This method is as follows:
    
    public bool Connect() {
    	StartTimer();
    	try {
    		Configure();
    		folders = iDSSServer.GetFolderList();
    		EndTimer();
    		return true;
    	}catch(Exception e) {
    		connectionError=e.ToString();
    		EndTimer();
    		return false;
    	}
    }
    
    protected void Configure() {
    	if(iDSSServer==null) iDSSServer = new IDSSServer.IDSS();
    	iDSSServer.Url=server;
    	if(iDSSServer.RequestSoapContext!=null && 
    iDSSServer.RequestSoapContext.Attachments.Count>=0) 
    iDSSServer.RequestSoapContext.Attachments.Clear();
    	if(iDSSServer.ResponseSoapContext!=null && 
    iDSSServer.ResponseSoapContext.Attachments.Count>=0) 
    iDSSServer.ResponseSoapContext.Attachments.Clear();
    
    	if(iDSSServer.AuthHeaderValue==null) {
    		auth = new IDSSServer.AuthHeader();
    		auth.Username=this.username;
    		auth.Password=this.password;
    		auth.Guid="";
    		iDSSServer.AuthHeaderValue=auth;
    	}
    	
    }
    
    
    This is simply creating an instance of our proxy class for the Web Service. It then ensures that the header authentication details are added to the request, and it clears any existing attachments that are on the Request or Response SOAP context. This is done because we will be reusing the same instance of the proxy object itself, and we want to have a clear Attachment list before using it each time.

    The most important line of code is where we are calling the GetFolderList(). It sends authentication information and retrieves the folder list simultaneously. If the Web Service throws an authentication error, no folders will be returned, and the user will be denied access to the folder listing and the service. If the authentication information is valid, the user will have a collection of folders to work with.

    Take time now to review the rest of the implementation of the Connection.cs file (and class). You will see that it is there in order to simplify and centralize the connection implementation using the proxy with the Web Service. It also handles all the necessary work with the DimeAttachments. I will cover these two methods (SaveFile, and GetFile) in more detail later.

    Viewing and Navigating Folders

    Once we have established a good connection with the service via the GetFolderList() method, we will also have a collection of available folders for this user. In the Browse.cs file source we are providing the end user with the ability to use this folder listing to load up a tree control on the form. Then, based on their actions (clicks within the tree), we are calling the service to get file listings for each folder, and finally downloading the specific file to the client machine's temporary cache folder. The Browse interface is shown below:

    In conclusion, I want to quickly cover how we interact with our proxy to download and upload our documents using DIME.

    Downloading Files

    In the Browse form, when we click the download arrow "<-", we are initiating a Web Service request to download the chosen file. Here is the relevant section of code for this that I pulled out of our Connection.cs file:

    
    public bool GetFile(string FullPath, string LocalFileName) {
    	StartTimer();
    	Configure();
    	iDSSServer.GetFile(FullPath);		
    
    	byte[] data = ConvertStreamToByteBuffer( 
    iDSSServer.ResponseSoapContext.Attachments[0].Stream );
    	if(System.IO.File.Exists(LocalFileName)) 
    System.IO.File.Delete(LocalFileName);
    	System.IO.FileStream outfile = System.IO.File.OpenWrite(LocalFileName);
    	outfile.Write(data, 0, data.Length);
    	outfile.Close();
    	EndTimer();
    	return true;
    
    }
    
    
    The first thing we do is call the GetFile() method on the proxy, which makes the call to the Web Service and pulls down the document specified via the DIME attachments. We are reading the first Attachment (0) off of the ResponseSoapContext. Next we convert that document to a byte[] buffer and save it to disk in our cache.

    Uploading Files

    The last piece of the puzzle has to do with uploading documents via DIME to our Web Service. This is done in almost the same way as how we did it on the server. First you create a stream to hold the content of the attachment ("stream"), and then you create an actual Microsoft.Web.Services.Dime.DimeAttachment object from the stream. Finally, add that attachment to the RequestSoapContext.Attachments collection (as we can see in the second method listed below).

    
    public static Microsoft.Web.Services.Dime.DimeAttachment 
    GetFileAsAttachment(string FullPath) {			
    	System.IO.FileStream stream = System.IO.File.OpenRead(FullPath);
    	Microsoft.Web.Services.Dime.DimeAttachment attach = new 
    Microsoft.Web.Services.Dime.DimeAttachment("0", 
    Microsoft.Web.Services.Dime.TypeFormatEnum.MediaType, stream);
    	return attach;			
    }
    
    public bool SaveFile(string FullPath, string LocalFileName) {
    	StartTimer();
    	Configure();
    	Microsoft.Web.Services.Dime.DimeAttachment attach = 
    GetFileAsAttachment(LocalFileName);
    	iDSSServer.RequestSoapContext.Attachments.Add(attach);
    	bool result = iDSSServer.SaveFile(FullPath);
    	EndTimer();
    	return result;
    }
    
    

    Conclusion

    This article explained how to use the new Web Service Enhancements from Microsoft to perform uploading and downloading of files with Web Services using the industry standard specification DIME. I also gave you a demonstration of how you could create a practical file-sharing application that could be used in an intranet environment.

    Also, within the download package I provided you with the Web Service, the Win Forms client, and an additional modified version for the Web. This allows for your Web site or Intranet application to connect to the Web Service and for you to interact with it via a Web form.

    References

    Web Services Enhancements for Microsoft .NET
    http://msdn.microsoft.com/webservices/building/wse/default.aspx

    Sending Files, Attachments, and SOAP Messages Via Direct Internet Message Encapsulation
    http://msdn.microsoft.com/msdnmag/issues/02/12/DIME/default.aspx

    DIME: Sending Binary Data with Your SOAP Messages
    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnservice/html/service01152002.asp

    DIME Specification Index Page
    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnglobspec/html/dimeindex.asp

    SOAP 1.2 Attachment Feature
    http://www.w3.org/TR/2002/WD-soap12-af-20020814/

    About the Author

    Robert Chartier has developed IT solutions for more than nine years with a diverse background in both software and hardware development. He is internationally recognized as an innovative thinker and leading IT architect with frequent speaking engagements showcasing his expertise. He's been an integral part of many open forums on cutting-edge technology, including the .NET Framework and Web Services. His current position as vice president of technology for Santra Technology (http://www.santra.com) has allowed him to focus on innovation within the Web Services market space.

    He uses expertise with many Microsoft technologies, including .NET, and a strong background in Oracle, BEA Systems, Inc.'s BEA WebLogic, IBM, Java 2 Platform Enterprise Edition (J2EE), and similar technologies to support his award-winning writing. He frequently publishes to many of the leading developer and industry support Web sites and publications. He has a bachelor's degree in Computer Information Systems.

    Robert Chartier can be reached at rob@santra.com.

  • Rate This Article
    Not HelpfulMost Helpful
    1 2 3 4 5
    Supporting Products/Tools
    FTP.NET
    FTP.NET is a file-transfer component for .NET languages (such as C# or VB.NET). FTP files directly from your application - either in synchronous or asynchronous mode. All popular FTP and proxy servers are supported. C# source code available.
    [Top]
    Other Articles
    Jul 7, 2005 - Hosting Indigo Web Services
    In the second article of his series on Indigo web services, Chris Peiris explains how to host an Indigo web service and examines the IIS, self hosting, and Windows Activation Service hosting options. He then provides step-by-step instructions and sample code for an IIS-hosted and self-hosted Indigo web service.
    [Read This Article]  [Top]
    Jun 8, 2005 - Indigo Programming Model
    In the first part of his series on Microsoft Indigo, Chris Peiris examines the basics of SOA, explains how Indigo fits into the picture and the problems it solves. He then introduces Indigo's programming model and finishes by building a sample Indigo web service using the Microsoft .Net Framework 2.0.
    [Read This Article]  [Top]
    Nov 10, 2004 - Business Intelligence with Microsoft SQL Server Reporting Services - Part 3
    Adnan Masood concludes his discussion of Microsoft SQL Server Analysis services and Microsoft SQL Server Reporting services. In the final part, he discusses Reporting Server web services and using custom code in reports.
    [Read This Article]  [Top]
    Jul 8, 2004 - Using IE's Web Service Behavior To Create Rich ASP.NET Applications
    This article explains the features of the IE Web service behavior and shows how to asynchronously communicate with an ASP.NET Web service directly from the client.
    [Read This Article]  [Top]
    Jul 6, 2004 - Using .NET and Excel 2003 To Validate E-Mails
    Calvin Luttrell shows how to validate e-mail addresses stored in Excel 2003 and provides a special function for solving that pesky problem Yahoo! mail servers cause.
    [Read This Article]  [Top]
    Jun 9, 2004 - Modifying Web Services Documentation
    This short article describes a quick and easy way to provide some security to an ASP.NET Web service by modifying its associated documentation file.
    [Read This Article]  [Top]
    Jun 2, 2004 - Kerberos Authentication with Web Services Enhancements 2.0
    Kerberos authentication is the cornerstone of Windows operating system authentication architecture. Web Services Enhancement 2.0 (WSE 2.0) extends Kerberos support to ASP.NET Web services. Chris Peiris explains the support for this new feature in WSE 2.0.
    [Read This Article]  [Top]
    Dec 15, 2003 - Realizing a Service-Oriented Architecture with .NET
    Chip Irek examines the architectural issues and component design issues of building a .NET application in a service-oriented architecture.
    [Read This Article]  [Top]
    Nov 24, 2003 - Consuming Asynchronous Web Services
    Thiru Thangarathinam shows how to use asynchronous Web services, Windows Service applications, server-based timer components and .NET XML API classes to create high-performance, scalable, and flexible applications.
    [Read This Article]  [Top]
    Nov 12, 2003 - Implementing Paging and XSLT Extensions Using XSLT in .NET - Part 2
    Part one showed how to transform XML data into HTML by using an XSL stylesheet from within a .NET application. This part explains how to make use of XSLT Extension objects and invoke a C# class method from an XSL stylesheet.
    [Read This Article]  [Top]
    Mailing List
    Want to receive email when the next article is published? Just Click Here to sign up.

    Support the Active Server Industry



    JupiterOnlineMedia

    internet.comearthweb.comDevx.commediabistro.comGraphics.com

    Search:

    Jupitermedia Corporation has two divisions: Jupiterimages and JupiterOnlineMedia

    Jupitermedia Corporate Info


    Legal Notices, Licensing, Reprints, & Permissions, Privacy Policy.

    Advertise | Newsletters | Tech Jobs | Shopping | E-mail Offers

    Solutions
    Whitepapers and eBooks
    Microsoft Article: Will Hyper-V Make VMware This Decade's Netscape?
    Microsoft Article: 7.0, Microsoft's Lucky Version?
    Microsoft Article: Hyper-V--The Killer Feature in Windows Server 2008
    Avaya Article: How to Feed Data into the Avaya Event Processor
    Microsoft Article: Install What You Need with Windows Server 2008
    HP eBook: Putting the Green into IT
    Whitepaper: HP Integrated Citrix XenServer for HP ProLiant Servers
    Intel Go Parallel Portal: Interview with C++ Guru Herb Sutter, Part 1
    Intel Go Parallel Portal: Interview with C++ Guru Herb Sutter, Part 2--The Future of Concurrency
    Avaya Article: Setting Up a SIP A/S Development Environment
    IBM Article: How Cool Is Your Data Center?
    Microsoft Article: Managing Virtual Machines with Microsoft System Center
    HP eBook: Storage Networking , Part 1
    Microsoft Article: Solving Data Center Complexity with Microsoft System Center Configuration Manager 2007
    MORE WHITEPAPERS, EBOOKS, AND ARTICLES
    Webcasts
    Intel Video: Are Multi-core Processors Here to Stay?
    On-Demand Webcast: Five Virtualization Trends to Watch
    HP Video: Page Cost Calculator
    Intel Video: APIs for Parallel Programming
    HP Webcast: Storage Is Changing Fast - Be Ready or Be Left Behind
    Microsoft Silverlight Video: Creating Fading Controls with Expression Design and Expression Blend 2
    MORE WEBCASTS, PODCASTS, AND VIDEOS
    Downloads and eKits
    Sun Download: Solaris 8 Migration Assistant
    Sybase Download: SQL Anywhere Developer Edition
    Red Gate Download: SQL Backup Pro and free DBA Best Practices eBook
    Red Gate Download: SQL Compare Pro 6
    Iron Speed Designer Application Generator
    MORE DOWNLOADS, EKITS, AND FREE TRIALS
    Tutorials and Demos
    How-to-Article: Preparing for Hyper-Threading Technology and Dual Core Technology
    eTouch PDF: Conquering the Tyranny of E-Mail and Word Processors
    IBM Article: Collaborating in the High-Performance Workplace
    HP Demo: StorageWorks EVA4400
    Intel Featured Algorhythm: Intel Threading Building Blocks--The Pipeline Class
    Microsoft How-to Article: Get Going with Silverlight and Windows Live
    MORE TUTORIALS, DEMOS AND STEP-BY-STEP GUIDES