Rashim's Blog

Posts Tagged ‘.NET


We are very well-versed that WCF service operations can be implemented asynchronously or synchronously .And the clients can call service operations synchronously or asynchronously since asynchronous service operations can be calling synchronously and vice versa. There are three ways to implement asynchronous operations

As a series of sequence, in this post, I am going to use IAsyncResult asynchronous operation but we should keep in mind that this pattern is no longer recommended for further development. If we know these three mechanisms of asynchronous operation it would be easier for us to architect our large distributed system based on asynchronous service. Before going to our implementation I would recommend you to have a look on APM Model first. I would like to Organize todays article in three steps; Service Implementation, Service Hosting and Client

Service Implementation

In IAsyncResult asynchronous system asynchronous operations require Begin and End methods.


[ServiceContract]
 public interface IMessageService
 {
 [OperationContract(AsyncPattern = true)]
 IAsyncResult BeginGetMessage(string message, AsyncCallback callback, object state);

string EndGetMessage(IAsyncResult asyncResult);
 }

In the service contract, I declare an asynchronous method pair according to the APM. The BeginGetMessage method takes a parameter, a callback object, and a state object, and returns an IAsyncResult while EndGetMessage method takes an IAsyncResult and returns the value. Since the service operation returns IAsyncResult we have to implement it first. And the implementation has been given below,


public class AsyncResult : IAsyncResult,IDisposable
 {
 private AsyncCallback _callback;
 private object _state;
 private ManualResetEvent _manualResetEvent;

public AsyncResult(AsyncCallback callback, object state)
 {
 _callback = callback;
 _state = state;
 _manualResetEvent = new ManualResetEvent(false);
 }

public bool IsCompleted
 {
 get { return _manualResetEvent.WaitOne(0, false); }
 }

public WaitHandle AsyncWaitHandle
 {
 get { return _manualResetEvent; }
 }

public object AsyncState
 {
 get { return _state; }
 }
 public ManualResetEvent AsyncWait
 {
 get { return _manualResetEvent; }

 }
 public bool CompletedSynchronously
 {
 get { return false; }
 }

public void Completed()
 {
 _manualResetEvent.Set();
 if (_callback != null)
 _callback(this);
 }

 public void Dispose()
 {
 _manualResetEvent.Close();
 _manualResetEvent = null;
 _state = null;
 _callback = null;
 }
 }

AsyncResult implements IAsyncResult that has some properties like AsyncCallback, state object and a ManualResetEvent, which handle waiting for asynchronous operation. IsCompleted is used to specify that the operation is completed asynchronously. In the Complete() method ManualResetEvent has been set, which means that the event is signaled now and any other awaiting thread can follow.

Now for our MessageServiceOperation I create MessageAsyncResult which just inherit from AsyncResult to add a Message property.


public class MessageAsyncResult : AsyncResult
 {
 public string Message { get; private set; }
 public MessageAsyncResult(string message, AsyncCallback callback, object state)
 : base(callback, state)
 {
 Message = message;
 }
 }

Now implementing the service operations.


public class MessageService : IMessageService
 {
 public IAsyncResult BeginGetMessage(string message, AsyncCallback callback, object state)
 {
 var replyMessage = string.Format("{0}{1}","Server says :",message);
 var messageAsyncResult = new MessageAsyncResult(replyMessage, callback, state);
 ThreadPool.QueueUserWorkItem(CompleteProcess, messageAsyncResult);

return messageAsyncResult;
 }

private void CompleteProcess(object state)
 {
 var messageAsyncResult = state as MessageAsyncResult;
 messageAsyncResult.Completed();
 }

public string EndGetMessage(IAsyncResult asyncResult)
 {
 var messageAsyncResult = asyncResult as MessageAsyncResult;
 messageAsyncResult.AsyncWait.WaitOne();
 return messageAsyncResult.Message;
 }
 }

In the BeginGetMessage () method I create an instance of MessageAsyncResult by passing appropriate parameters to it then call ThreadPool.QueueUserWorkItem() method to add a method to waiting queue for execution. The method CompleteProcess() will run whenever a thread becomes available and it finally call the Completed() method to release the thread and allow the other operations to execute. In the EndGetMessage () method, I call the WaitOne() method of its ManualResetEvent to wait until the current execution ends then return the Result property.

Service Hosting

This is also very simple. Here I have used a console app which will be used as a server,


class Program
 {
 static void Main(string[] args)
 {
 var svcHost = new ServiceHost(typeof(MessageService));
 Console.WriteLine("Available Endpoints :\n");
 svcHost.Description.Endpoints.ToList().ForEach(endpoints => Console.WriteLine(endpoints.Address.ToString()));
 svcHost.Open();
 Console.ReadLine();
 }
 }

And the configuration for that,


<configuration>
 <system.serviceModel>
 <behaviors>
 <serviceBehaviors>
 <behavior name="">
 <serviceMetadata httpGetEnabled="true" />
 <serviceDebug includeExceptionDetailInFaults="false" />
 </behavior>
 </serviceBehaviors>
 </behaviors>
 <services>
 <service name="Rashim.Rnd.WCF.Asynchronous.Services.MessageService">
 <endpoint address="" binding="basicHttpBinding" contract="Rashim.Rnd.WCF.Asynchronous.Services.IMessageService">
 <identity>
 <dns value="localhost" />
 </identity>
 </endpoint>
 <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
 <host>
 <baseAddresses>
 <add baseAddress="http://localhost/Rashim.Rnd.WCF.Asynchronous.Services/" />
 </baseAddresses>
 </host>
 </service>
 </services>
 </system.serviceModel>
</configuration>

Client

Now how client could consume this service.? Here I have given a simple console app to consume this service,


public class Program
 {
 static void Main(string[] args)
 {
 var channelFactory = new ChannelFactory<IMessageService>("MessageServiceEndpoint");
 var proxy = channelFactory.CreateChannel();
 var message = Console.ReadLine();
 while (message.Equals("exit",StringComparison.CurrentCultureIgnoreCase)==false)
 {
 proxy.BeginGetMessage(message, ClientCallBack, proxy);
 message = Console.ReadLine();
 }
 }

private static void ClientCallBack(IAsyncResult ar)
 {
 var res = ar.AsyncState as IMessageService;
 if (res != null)
 {
 var message = res.EndGetMessage(ar);
 Console.WriteLine(message);
 }
 }
 }

And the configuration file for this is,


<configuration>
 <system.serviceModel>
 <bindings />
 <client>
 <endpoint address="http://localhost/Rashim.Rnd.WCF.Asynchronous.Services/"
 binding="basicHttpBinding" contract="Rashim.Rnd.WCF.Asynchronous.Services.IMessageService"
 name="MessageServiceEndpoint">
 <identity>
 <dns value="ServerCertificate" />
 </identity>
 </endpoint>
 </client>
 </system.serviceModel>
</configuration>

That’s it. Download Source code.

Advertisements

Though Performance blocking and Sluggishness are the tailbacks for any application, we can easily overcome these bottlenecks by using asynchronous programming. But old-style practice for asynchronous programming is not way easy enough to write, debug and maintain. So what is the contemporary approach??

Well, In my view, this is Task based asynchronous programming, which is updated in .Net 4.5 through the use of keywords await and async. But what do async and await do? async and await are the way of controlling continuation. When a method uses the async keyword, it means it is an asynchronous method, which might have an await keyword inside, and if it has an await keyword, async will activate it. So, simply async activates the await, from which point, the asynchronous has been started. There is a nice explanation that has been given here.

In WCF we can also consider an asynchronous operation while the service operation creates a delaying call. There are three ways to implement asynchronous operations

In this post I am going to use task-based asynchronous operation since this is the most contemporary strategy.

Okay. Let’s move to the code,

A very simple Service contract such as,

 [ServiceContract]
 public interface IMessage
 {
     [OperationContract]
     Task<string> GetMessages(string msg);
 }

With this simple contract, the implementation is just straight forward,

 public class MessageService : IMessage
 {
    async Task<string> IMessage.GetMessages(string msg)
    {
       var task = Task.Factory.StartNew(() =>
                                      {
                                          Thread.Sleep(10000);
                                          return "Return from Server : " + msg;
                                      });
      return await task.ConfigureAwait(false);
    }
 }

Here, the method is marked with the async keyword, which means it might use await keyword inside. It also means that the method will be able to suspend and then resume asynchronously at await points. Moreover, it points the compiler to boost the outcome of the method or any exceptions that may happen into the return type.

Service hosting,

 class Program
 {
     static void Main(string[] args)
     {
        var svcHost = new ServiceHost(typeof (MessageService));
        Console.WriteLine("Available Endpoints :\n");
        svcHost.Description.Endpoints.ToList().ForEach(endpoints=> Console.WriteLine(endpoints.Address.ToString()));
        svcHost.Open();
        Console.ReadLine();
     }
 }

Finally Service Configuration,

<?xml version="1.0"?>
 <configuration>
     <system.serviceModel>
       <services>
          <service name="Rashim.RND.WCF.Asynchronous.ServiceImplementation.MessageService">
             <host>
                 <baseAddresses>
                     <add baseAddress="net.Tcp://localhost:8732/"/>
                     <add baseAddress="http://localhost:8889/"/>
                 </baseAddresses>
             </host>
             <endpoint address="Tcp" binding="netTcpBinding" contract="Rashim.RND.WCF.Asynchronous.Services.IMessage"/>
             <endpoint address="Http" binding="basicHttpBinding" contract="Rashim.RND.WCF.Asynchronous.Services.IMessage">
                 <identity>
                      <dns value="localhost"/>
                 </identity>
             </endpoint>
             <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange"/>
             <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
          </service>
       </services>
       <behaviors>
          <serviceBehaviors>
             <behavior>
                 <serviceMetadata/>
             </behavior>
          </serviceBehaviors>
       </behaviors>
     </system.serviceModel>
     <startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/></startup>
</configuration>

After Configuring the service,we need to configure the client app to consume the service.

A simple Console Application(Client),

class Program
 {
    static void Main(string[] args)
    {
       GetResult();
       Console.ReadLine();
    }

    private async static void GetResult()
    {
       var client = new Proxy("BasicHttpBinding_IMessage");
       var task = Task.Factory.StartNew(() => client.GetMessages("Hello"));
       var str = await task;
       str.ContinueWith(e =>
       {
          if (e.IsCompleted)
           {
              Console.WriteLine(str.Result);
           }
       });
      Console.WriteLine("Waiting for the result");
    }
 }

Client Configuration,

<?xml version="1.0"?>
 <configuration>
   <system.serviceModel>
     <bindings>
       <basicHttpBinding>
         <binding name="BasicHttpBinding_IMessage" />
       </basicHttpBinding>
     </bindings>
     <client>
       <endpoint address="http://localhost:8889/Http" binding="basicHttpBinding"
          bindingConfiguration="BasicHttpBinding_IMessage" contract="Rashim.RND.WCF.Asynchronous.Services.IMessage"
           name="BasicHttpBinding_IMessage" />
     </client>
   </system.serviceModel>
 </configuration>

Finally,proxy class is given below through which the client will consume the services.

public class Proxy : ClientBase<IMessage>, IMessage
 {
    public Proxy()
    {
    }
    public Proxy(string endpointConfigurationName) :
    base(endpointConfigurationName)
    {
    }
    public Task<string> GetMessages(string msg)
    {
      return Channel.GetMessages(msg);
    }
 }

That’s it. Very easy stuff though. You can download the source code from here.


Sometimes we need to save data to Excel file using Microsoft Excel. To do that we might need to create the Excel file, need to create table on that with some columns and then save data to the table of Excel file. This is pretty easy enough. Have a look on that.

Save Data to Excell Table,


        private void InsertDataOnExcellTable(string submitttedExcellPath, Test submittedExcellData)
        {
            if (!string.IsNullOrEmpty(submitttedExcellPath) && submittedExcellData != null)
            {
                if (!string.IsNullOrEmpty(submittedExcellData.FileName))
                {
                    var fullFileName = submitttedExcellPath + Path.DirectorySeparatorChar + submittedExcellData.FileName;

                    var xlFileExtension = ".xls";

                    if (!fullFileName.Contains(xlFileExtension))
                    {
                        fullFileName = fullFileName + xlFileExtension;
                    }

                    string connectionString = ConnectionString.GetConStr(fullFileName);

                    if (!string.IsNullOrEmpty(connectionString))
                    {
                        if (this.CreateTableOnExcell(fullFileName, connectionString) == true)
                        {
                            lock (new object())
                            {
                                System.Data.OleDb.OleDbConnection myConnection;
                                var myCommand = new System.Data.OleDb.OleDbCommand();
                                string sql = null;

                                myConnection = new System.Data.OleDb.OleDbConnection(connectionString);
                                myConnection.Open();
                                myCommand.Connection = myConnection;
                                sql = "Insert into [Sheet1$] "
                                + "( "
                                + "[Title],[FirstName],[Surname],[Email],[TelePhoneNumber],[OrderNumber],[SubmissionDate]"
                                + " )"
                                + " values "
                                + "('" + submittedExcellData.Title + "','" + submittedExcellData.FirstName + "','" + submittedExcellData.SurName + "','" + submittedExcellData.Email + "','" + submittedExcellData.TelePhoneNumber + "','" + submittedExcellData.OrderNumber + "','" + submittedExcellData.SubmissionDate + "')";

                                myCommand.CommandText = sql;
                                myCommand.ExecuteNonQuery();
                                myConnection.Close();
                            }
                        }
                    }
                }
            }
        }

Create table on Excell file,


        private bool CreateTableOnExcell(string submittedFullPath, string submittedConnStr)
        {
            if (!string.IsNullOrEmpty(submittedConnStr) && !string.IsNullOrEmpty(submittedFullPath))
            {
                if (this.CreateExcellFile(submittedFullPath))
                {
                    lock (new object())
                    {
                        OleDbConnection connExcel = new OleDbConnection(submittedConnStr);
                        OleDbCommand cmdExcel = new OleDbCommand();
                        cmdExcel.Connection = connExcel;
                        System.Data.DataTable excelSchema = null;

                        try
                        {
                            ////Check if the Sheet Exists
                            connExcel.Open();
                            excelSchema = connExcel.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
                        }
                        catch
                        {
                        }
                        finally
                        {
                            connExcel.Close();
                        }

                        DataRow[] dr = excelSchema != null ? excelSchema.Select("TABLE_NAME = 'Sheet1'") : null;

                        ////if not Create the Sheet
                        if (dr == null || dr.Length == 0)
                        {
                            string excelCommand = "CREATE TABLE";

                            string sheetName = "[Sheet1]";

                            ////All Column Name
                            StringBuilder tableColumn = new StringBuilder();
                            tableColumn.Append("(");
                            tableColumn.Append("Title varchar(20)");
                            tableColumn.Append(",");

                            tableColumn.Append("FirstName varchar(20)");
                            tableColumn.Append(",");

                            tableColumn.Append("Surname varchar(20)");
                            tableColumn.Append(",");

                            tableColumn.Append("Email varchar(20)");
                            tableColumn.Append(",");

                            tableColumn.Append("TelePhoneNumber varchar(20)");
                            tableColumn.Append(",");

                            tableColumn.Append("OrderNumber varchar(20)");
                            tableColumn.Append(",");

                            tableColumn.Append("SubmissionDate varchar(20)");
                            tableColumn.Append(")");
                            tableColumn.Append(";");

                            StringBuilder exelQuery = new StringBuilder();
                            exelQuery.Append(excelCommand);
                            exelQuery.Append(" ");
                            exelQuery.Append(sheetName);
                            exelQuery.Append(" ");
                            exelQuery.Append(tableColumn.ToString());

                            if (cmdExcel != null)
                            {
                                cmdExcel.CommandText = exelQuery.ToString();
                                connExcel.Open();
                                cmdExcel.ExecuteNonQuery();
                                connExcel.Close();
                            }
                        }
                    }

                    return true;
                }
            }

            return false;
        }

Create Excel file,


        private bool CreateExcellFile(string submittedFullPath)
        {
            if (!string.IsNullOrEmpty(submittedFullPath))
            {
                lock (new object())
                {
                    if (!File.Exists(submittedFullPath))
                    {
                        ////Ex = Microsoft.Office.Interop.Excel;
                        Ex.Application exelApp = null;
                        Ex.Workbook exelWorkBook = null;
                        Ex.Worksheet exelWorkSheet = null;
                        object misValue = System.Reflection.Missing.Value;

                        try
                        {
                            ////Create an Excell Application
                            exelApp = new Ex.ApplicationClass();

                            if (exelApp != null)
                            {
                                if (exelApp.Workbooks != null)
                                {
                                    ////Add an Workbook to the current Excell Application
                                    exelWorkBook = exelApp.Workbooks.Add(misValue);
                                }
                            }

                            if (exelWorkBook != null)
                            {
                                ////Getting Sheet1
                                exelWorkSheet = (Ex.Worksheet)exelWorkBook.Worksheets.get_Item(1);

                                if (exelWorkSheet != null)
                                {
                                    //// Naming the Table Data Column
                                    exelWorkSheet.Cells[1, 1] = "Title";
                                    exelWorkSheet.Cells[1, 2] = "FirstName";
                                    exelWorkSheet.Cells[1, 3] = "Surname";
                                    exelWorkSheet.Cells[1, 4] = "Email";
                                    exelWorkSheet.Cells[1, 5] = "TelePhoneNumber";
                                    exelWorkSheet.Cells[1, 6] = "OrderNumber";
                                    exelWorkSheet.Cells[1, 7] = "SubmissionDate";
                                }

                                ////Save the Excell file to its Specified location
                                exelWorkBook.SaveAs(submittedFullPath, Ex.XlFileFormat.xlWorkbookNormal, misValue, misValue, misValue, misValue, Ex.XlSaveAsAccessMode.xlExclusive, misValue, misValue, misValue, misValue, misValue);
                            }
                        }
                        catch
                        {
                        }
                        finally
                        {
                            if (exelWorkBook != null)
                            {
                                exelWorkBook.Close(true, misValue, misValue);
                            }

                            if (exelApp != null)
                            {
                                exelApp.Quit();
                            }
                        }

                        this.ReleaseObject(exelWorkSheet);
                        this.ReleaseObject(exelWorkBook);
                        this.ReleaseObject(exelApp);
                    }

                    return true;
                }
            }

            return false;
        }

Release the Object by force,

private void ReleaseObject(object submittedObj)
        {
            try
            {
                //// By force realeasing the Object if the Garbage Collector not doing it right now
                System.Runtime.InteropServices.Marshal.ReleaseComObject(submittedObj);
            }
            catch
            {
            }
            finally
            {
                GC.Collect();
            }
        }

And then the Connection String,


        public static string GetConStr(string submittedPath)
        {
            var connectionString = string.Empty;

            if (!string.IsNullOrEmpty(submittedPath))
            {
                connectionString = @"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + submittedPath + ";Extended Properties=\"Excel 8.0;HDR=YES;IMEX=0\"";
            }

            return connectionString;
        }


Object Serialization, which is also called deflating or marshaling, is a progression through which an object’s state is converted into some serial data format, such as XML or binary format, in order to be stowed for some advanced use whereas Deserialization is the opposite process of Serialization which is also called inflating or unmarshalling. The code showing the very simple way for serializing and deserializing from XML to any Object and vice versa as well,

Use this method for serialization,


        public static string Serialize<T>(T value)
        {
            if (value == null)
            {
                return null;
            }

            XmlSerializer serializer = new XmlSerializer(typeof(T));

            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Encoding = new UnicodeEncoding(false, false);
            settings.Indent = false;
            settings.OmitXmlDeclaration = false;

            using (StringWriter textWriter = new StringWriter())
            {
                using (XmlWriter xmlWriter = XmlWriter.Create(textWriter, settings))
                {
                    serializer.Serialize(xmlWriter, value);
                }

                return textWriter.ToString();
            }
        }

Use this method for Deserialization,


        public static T Deserialize<T>(string xml)
        {
            if (string.IsNullOrEmpty(xml))
            {
                return default(T);
            }

            XmlSerializer serializer = new XmlSerializer(typeof(T));

            XmlReaderSettings settings = new XmlReaderSettings();

            using (StringReader textReader = new StringReader(xml))
            {
                using (XmlReader xmlReader = XmlReader.Create(textReader, settings))
                {
                    return (T)serializer.Deserialize(xmlReader);
                }
            }
        }

%d bloggers like this: