AspNet4YouTop 10sDevelopers WorldForums
Home
About
ASPNet Books
ASPNet Sites
ASPNet Hosters
View Articles
Search Articles
Authors
View Forums
 
Quick Menus
HOME
About
AspNet4You Forums
Articles
Authors
Search
Articles Summary
Articles(RSSFeed)
AspNet Books
AspNet Sites
AspNet Hosters
 Top 10 ASP.NET Books 
Professional ASP.NET 1.1
Essential ASP.NET With Examples in C#
ASP.NET Unleashed
Programming Data Driven Web Applications with ASP.NET
Professional ASP.NET Web Services
Beginning ASP.NET 1.1 with Visual C# .NET 2003
Programming Microsoft ASP.NET
Beginning ASP.NET Databases Using VB.NET
ASP.NET Security
Developing Microsoft ASP.NET Server Controls and Components
More...
 Top 10 ASP.NET Hosters 
WebHost4Life
DiscountASP.NET
MaximumASP
Brinkster
ORCS Web
myhosting.com
ISQSolutions
ASPwebhosting.com, LLC
Active ISP
Aquest Hosting
More...
 Top 10 ASP.NET Sites 
Asp.Net
GotDotNet
4GuysFromRolla.com
123aspx.com
EggHeadCafe.com
CShrp.Net
.NET 247
DevelopersDex.com
Csharp-Corner.com
dotnetspider
More...
Search Articles
Google
ASPNET4YOU      
Category:   Search Type:   Match Type:  
Distributed Data Access (.Net Remoting)
Author: Saha, ProdipPosted: 9/18/2005 9:50:52 PM

Distributed Data Access (.Net Remoting)

NET Remoting enables you to build widely distributed applications easily, whether application components are all on one computer or spread out across the entire world. .Net Remoting is flexible and easily customizable yet many of us found it is hard to implement in real life. Yes, it is relatively easy if you know how to plug in all the pieces together and if you do them correctly in each step. In this article I would like to show you how to consume remote data access services from ASP.Net and Windows clients. 

Download the complete source code Remotings.zip(568KB)

Ingo Rammer has done an excellent job explaining different Design Patterns of .Net Remoting. After reading the book and researched each of the design pattern, I have settled on the following pattern-

Service: OleDbDataAccess with an Interface; Factory Pattern; Singleton
Host: Windows Service as trusted sub-system; TcpChannel; Binary Formatter
Client: InterfaceOleDbDataAccess; TcpChannel; Binary Formatter

In order to implement .Net Remoting we need three things- a remotable component (service), a listener application (host) and a client application. There are many ways to host the remote component and there are many ways to configure the host and client. We will use a Windows Service to host the service component. What about the communication channel and formatter? We will waste no time by comparing different channels (Tcp or Http) or different formatters (Binary or Soap). Tcp over Binary is proven to be faster. So, we will select the Tcp channel with Binary formatter to communicate between the clients and service.

Here is the breakdown of the distributed systems and it is very important that you read all sections before jumping to actual coding-

  • Remotable Component (Service): I have been using Data Access component that I have downloaded from Microsoft Pattern and Practice and modified it to meet the need. We want to take leverage of the component. This way we keep our focus on .Net Remoting. You will find these data access components as part of the download.
  • Listener Application (Host): We will use a Windows Service as our listener host application to host the remotable Data Access component. Visual Studio .Net 2003 let�s you create a Windows Service application very easily but there is more to it. What about the installing this Windows Service and start it from control panel? Sounds familiar but it requires some special techniques. We will cover them all in this article.
  • Client Application (Client): Our article will be incomplete without having an example of a client talking to remote service. We will show how remote service can be consumed by both ASP.Net and Windows applications.

Once again, we are not going to build the Remote Component because it is already there and ready to be used. So, let us focus on how to build a host application and a client application.

  • Create a new Listener Application (Windows Service host):
    1. Create a new Windows Service project. Visual Studio creates an empty service class called Service1. Rename it RemotingServiceHost.
    2. Rename the Service1.cs to RemotingServiceHost.cs. Be sure to modify the ServiceToRun class name in the Main method.
    3. Visual Studio .Net 2003 takes care of most the coding for this Windows Service. We just need to override the onStart method of the ServiceBase class to configure our Remoting objects. You will find the complete codes in the download but below is how it looks. As you can see there is no reference to any service becasue the host is independent of services.
      protected override void OnStart(string[] args)
      {
      	try
      	{
      		//Configure the Service through config file
      		RemotingConfiguration.Configure(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile) ;
      
      		//Config the Channel and provider through codes
      		BinaryServerFormatterSinkProvider provider = new BinaryServerFormatterSinkProvider();
      		provider.TypeFilterLevel =TypeFilterLevel.Full;
      		IDictionary props = new Hashtable();
      		props["port"] = 9000;
      		IChannel ServerChannel = new TcpChannel(props, null, provider);
      		ChannelServices.RegisterChannel( ServerChannel );
      	}
      	catch(Exception ex)
      	{
      		//If the configuration run into error, service will start with error.
      		//verify the event log for more info.
      		System.Diagnostics.EventLog.WriteEntry("RemotingServiceHost",ex.Message);
      	}
      	
      }
      						
    4. Right click on the RemotingServiceHost project and click on Properties-
      1. Set the Assembly Name property to RemotingServiceHost
      2. Set the Default Namespace property to RemotingServiceHost
      3. Set the Startup Object to RemotingServicesHost.RemotingServicesHost
      4. Click ok to close the dialog box.
    5. Right click on the RemotingServiceHost project choose Add New Item. Select Application Configuration and name it to App.config. You will find the complete configuration in the download but there is only one line of configuration that we need to take a note here-
      <wellknown 
      	type="ASPNET4YOU.COM.Implementation.OleDbDataAccess.OleDbHelperFactory, ImplementationOleDbDataAccess" 
      	objectUri="RemoteOleDbDataAccess.rem" 
      	mode="Singleton" 
      	displayName="RemoteOleDbDataAccess"
      />
      
    6. Add Installer: This is required to install the service. Go to the Design view of the RemotingServiceHost and right click on it. Click Add Installer. By default, a component class containing two installers is added to your project. The component is named ProjectInstaller, and the installers it contains are the installer for your service and the installer for the service's associated process.
    7. Open the ProjectInstaller in design view. Click on serviceInstaller1.
    8. In the Properties window-
      1. Set the ServiceName property to RemotingServicesHost.
      2. Set the DisplayName property to RemotingServicesHost.
      3. Set the StartType to Automatic
    9. Open the ProjectInstaller in design view. Click on serviceProcessInstaller1.
    10. In the Properties window
      1. Set the Account property to LocalSystem
    11. Build the project.
    Now that we have created the Windows Service, we have to find a way to deploy it. We will have to create a setup project. A setup project will install the compiled project files and run the installers needed to run the Windows service. To create a complete setup project, you will need to add the project output, RemotingServicesHost.exe, to the setup project and then add a custom action to have RemotingServicesHost.exe installed.
  • To create a setup project for RemotingServicesHost
    1. On the File menu, point to Add Project, and then choose New Project.
    2. In the Project Types pane, select the Setup and Deployment Projects folder.
    3. In the Templates pane, select Setup Project. Name the project RemotingServicesHostSetup.

      A setup project is added to the solution. Next you will add the output from the Windows service project, RemotingServicesHost.exe, to the setup.

      To add RemotingServicesHost.exe to the setup project-
      1. In Solution Explorer, right-click RemotingServicesHostSetup, point to Add, then choose Project Output. The Add Project Output Group dialog box appears.
      2. RemotingServicesHost is selected in the Project box.
      3. From the list box, select Primary Output, and click OK.

      A project item for the primary output of RemotingServicesHost is added to the setup project. Now add a custom action to install the RemotingServicesHost .exe file.

      To add a custom action to the setup project-
      1. In Solution Explorer, right-click the setup project, point to View, then choose Custom Actions. The Custom Actions editor appears.
      2. In the Custom Actions editor, right-click the Custom Actions node and choose Add Custom Action. The Select Item in Project dialog box appears.
      3. Double-click the application folder in the list box to open it, select primary output from RemotingServicesHost (Active), and click OK. The primary output is added to all four nodes of the custom actions � Install, Commit, Rollback, and Uninstall.
      4. Build the setup project. A msi package will be created. You will need to run this msi package to install the windows service. Once installed you can view the service in the control panel. You will need to start the service manually for the first time only. It will start automatically subsequently (according to our setting).

      Please note that you need to run the setup msi package only once. For any subsequent changes-
      1. Stop the service- RemotingServicesHost
      2. Copy the RemotingServicesHost.exe and other dependent file(s) to the installed directory.
      3. Start the service- RemotingServicesHost
  • Create a Windows Client:

    As we mentioned earlier, this article will be incomplete if I did not show how to consume the remote service from either a windows or a web client. Before we can use the remote service, we need to make sure the Windows Service Host has been started from the control panel. We also need to take a note of the configuration from RemotingServicesHost.exe.config file.

    There is nothing in the client configuration file. So, we need to configure the channel and Formatter in code. We need to register the channel only once for the application. So, I have added the configuration related code in Form_Load event:
    private void RemoteClient_Load(object sender, System.EventArgs e)
    {
    	try
    	{
    		RemotingConfiguration.Configure("RemoteClient.exe.config") ;
    		IDictionary props = new Hashtable();
    		props["port"] = 0;
    		
    		BinaryClientFormatterSinkProvider provider = new BinaryClientFormatterSinkProvider();
    		IChannel ClientChannel = new TcpChannel(props,provider,null);
    		ChannelServices.RegisterChannel( ClientChannel );
    	}
    	catch(Exception ex)
    	{
    		
    	}
    }
    								

    Ok, we are now ready to use the remote data access object. One of the important benefits of using Interface is- you don't need the implementation dll in the client project. All we need is interface dll. You will get the complete source codes in the download but I will show you below how you can retrieve records from Northwind SQL database.

    Execute Free SQL:
    private void btnExecSQL_Click(object sender, EventArgs e)
    {
    	try
    	{
    		//Change the machine name in the uri: tcp://remote-server-name:9000/RemoteOleDbDataAccess.rem
    		IOleDbHelperFactory proxy=(IOleDbHelperFactory)Activator.GetObject(typeof(IOleDbHelperFactory),"tcp://remote-server-name:9000/RemoteOleDbDataAccess.rem");
    		IOleDbHelper oData=proxy.CreateInstance();	
    		
    		DataSet ds=oData.ExecuteDataset(connstring,CommandType.Text,"SELECT * FROM CUSTOMERS");
    		if(ds!=null)
    		{
    			DataTable dtCustomer=ds.Tables[0];
    			if(dtCustomer!=null)
    			{
    				dataGrid1.SetDataBinding(dtCustomer.DefaultView,"");
    			}
    		}
    	}
    	catch(Exception ex)
    	{
    		//do something
    	}
    }
    					


    Execute Stored Procedure:
    private void btnExecSP_Click(object sender, EventArgs e)
    {
    	try
    	{
    		
    		string strStoredProcName="CustOrdersDetail";
    		
    		// Set up parameters
    		OleDbParameter[] arParms = new OleDbParameter[2];
    		arParms[0] = new OleDbParameter("@RETURN_VALUE",OleDbType.Integer);
    		arParms[0].Direction=ParameterDirection.ReturnValue;
    		
    		arParms[1] = new OleDbParameter("@OrderID",OleDbType.Integer);
    		arParms[1].Direction=ParameterDirection.Input;
    		arParms[1].Value=10248;
    
    		//Change the machine name in the uri: tcp://remote-server-name:9000/RemoteOleDbDataAccess.rem
    		IOleDbHelperFactory proxy=(IOleDbHelperFactory)Activator.GetObject(typeof(IOleDbHelperFactory),"tcp://remote-server-name:9000/RemoteOleDbDataAccess.rem");
    		IOleDbHelper oData=proxy.CreateInstance();	
    		
    		DataSet ds=oData.ExecuteDataset(connstring,CommandType.StoredProcedure,strStoredProcName,arParms);
    		if(ds!=null)
    		{
    			DataTable dtCustomer=ds.Tables[0];
    			if(dtCustomer!=null)
    			{
    				dataGrid1.SetDataBinding(dtCustomer.DefaultView,"");
    			}
    		}
    
    	}
    	catch(Exception ex)
    	{
    		//do something
    	}
    }
    					

  • Create an ASP.Net Client:

    You would configure the remoting information very similar way as described in windows client section of this article. We need to register the channel only once for the application. So, I have added the configuration related code in Application_Start event in Global.asax.cs file:
    protected void Application_Start(Object sender, EventArgs e)
    {
    	try
    	{
    		
    		IDictionary props = new Hashtable();
    		props["port"] = 0;
    		
    		BinaryClientFormatterSinkProvider provider = new BinaryClientFormatterSinkProvider();
    		IChannel ClientChannel = new TcpChannel(props,provider,null);
    		ChannelServices.RegisterChannel( ClientChannel );
    	}
    	catch(Exception ex)
    	{
    		//do something
    	}
    }
    								

    Making calls to SQL database from ASP.Net application is identical to that of windows application. Below you will find codes showing how to execute free sql and to execute a stored procedure with parameters over .Net Remoting. Again, you will find the complete code examples in the download.

    Execute Free SQL:
    private void btnExecSQL_Click(object sender, System.EventArgs e)
    {
    	Label1.Text="";
    
    	try
    	{
    		DateTime startT=DateTime.Now;
    		//Change the machine name in the uri: tcp://remote-server-name:9000/RemoteOleDbDataAccess.rem
    		IOleDbHelperFactory proxy=(IOleDbHelperFactory)Activator.GetObject(typeof(IOleDbHelperFactory),"tcp://remote-server-name:9000/RemoteOleDbDataAccess.rem");
    		IOleDbHelper oData=proxy.CreateInstance();	
    		
    		DataSet ds=oData.ExecuteDataset(connstring,CommandType.Text,"SELECT * FROM CUSTOMERS");
    		if(ds!=null)
    		{
    			DataTable dtCustomer=ds.Tables[0];
    			if(dtCustomer!=null)
    			{
    				DataGrid1.DataSource=dtCustomer.DefaultView;
    				DataGrid1.DataBind();
    			}
    		}
    		
    		DateTime endT=DateTime.Now;
    		TimeSpan t=endT.Subtract(startT);
    		Label1.Text="Time Spent in Milliseconds:" +t.Milliseconds.ToString();
    	}
    	catch(Exception ex)
    	{
    		Label1.Text=ex.Message;
    	}
    }
    					


    Execute Stored Procedure:
    private void btnExecSP_Click(object sender, System.EventArgs e)
    {
    	try
    	{
    		
    		DateTime startT=DateTime.Now;
    
    		string strStoredProcName="CustOrdersDetail";
    		
    		// Set up parameters
    		OleDbParameter[] arParms = new OleDbParameter[2];
    		arParms[0] = new OleDbParameter("@RETURN_VALUE",OleDbType.Integer);
    		arParms[0].Direction=ParameterDirection.ReturnValue;
    		
    		arParms[1] = new OleDbParameter("@OrderID",OleDbType.Integer);
    		arParms[1].Direction=ParameterDirection.Input;
    		arParms[1].Value=10248;
    
    		IOleDbHelperFactory proxy=(IOleDbHelperFactory)Activator.GetObject(typeof(IOleDbHelperFactory),"tcp://remote-server-name:9000/RemoteOleDbDataAccess.rem");
    		IOleDbHelper oData=proxy.CreateInstance();	
    		
    		DataSet ds=oData.ExecuteDataset(connstring,CommandType.StoredProcedure,strStoredProcName,arParms);
    		if(ds!=null)
    		{
    			DataTable dtCustomer=ds.Tables[0];
    			if(dtCustomer!=null)
    			{
    				DataGrid1.DataSource=dtCustomer.DefaultView;
    				DataGrid1.DataBind();
    			}
    		}
    		
    		DateTime endT=DateTime.Now;
    		TimeSpan t=endT.Subtract(startT);
    		Label1.Text="Time Spent in Milliseconds:" +t.Milliseconds.ToString();
    
    		
    
    	}
    	catch(Exception ex)
    	{
    		Label1.Text=ex.Message;
    	}
    }
    					

Conclusion:
Intention of this article is to provide you enough information to communicate across different application domain over .Net Remoting. It's important that you read all the steps described in this articles to avoid common mistakes.

Have a question or comment? Please visit Questions & Answers Forum 


Prodip K. Saha
The Architect of WWW.ASPNET4YOU.COM.

Terms and Conditions