Posts

....
Technical Blog for .NET Developers ©

Showing posts with label wcf. Show all posts
Showing posts with label wcf. Show all posts

Wednesday, July 17, 2019

WCF One Way Dual Methods

WCF Services can declare methods which are invoked in one way mode, this implies the method will be called but the client side will not expect a reply, so will continue its operations without time leaks waiting for a response. This configuration is optimal for operations which don't require feedback results

OneWay methods can be bi-directionals, through a dual configuration, allowing client and server initiate invocation calls to each other. This mechanism is very useful for long-running processes in case the client expects a reply

In this post we develop a dual communication through a wsDualHttpBinding endpoint. These are the key points of the mechanism:

  • The service will expose an interface with the definition of the callback method, this method will be also marked as OneWay
  • This interface will be implemented in the client side
  • The OneWay method in the service will use this implementation to communicate with the client side once finish tasks
  • The client side must not dispose the InstanceContext with the server til the communication ends, the callback from the server will be treated as an event


The first step will be the definition of the interface in the service

    
    [ServiceContract(CallbackContract = typeof(IBookServiceCallBack))]
    public interface IBookService
    {
        [OperationContract]
        int AddBook(string title, string isbn, string synopsis, int idAuthor);

        [OperationContract]
        int AddAuthor(string firstName, string lastName, string biography);

        [OperationContract(IsOneWay = true)]
        void SendNewTitlesToSubscriptors(DateTime booksAddedAfterDate);
    }
    


And this is the definition of IBookServiceCallBack


    [ServiceContract] 
    public interface IBookServiceCallBack
    {
        [OperationContract(IsOneWay = true)]
        void NotifyClient(string message);
    }
    


We will focus on the method SendNewTitlesToSubscriptors, which will invoke the notification event on the client side

    
    public void SendNewTitlesToSubscriptors(DateTime booksAddedAfterDate)
    {
        _subscriptorManager.SendNewTitlesToSubscriptors(booksAddedAfterDate);

        INotificationServiceCallBack notificationSend =
            OperationContext.Current.GetCallbackChannel();

        notificationSend.NotifyClient(string.Format(
            "New titles added since {0} have been sent successfully", booksAddedAfterDate));
    }
    


With this configuration the client reference will add the interface IBookServiceCallBack

      <service name="BookService.BookService">
        <endpoint address="CallBackService" 
        binding="wsDualHttpBinding" contract="BookService.IBookService"/>
      </service>


Now the code in the client side:


    private InstanceContext instance
    {
        get { return new InstanceContext(new BookStoreNotificationHandler()); }
    }

    private BookServiceClient client
    {
        get { return new BookServiceClient(instance); }
    }

    private void btnSendNewTitles_Click(object sender, RoutedEventArgs e)
    {
        DateTime booksAddedAfterDate = dpBooksAddedFromDate.SelectedDate.Value;

        Thread threadSendNewTitles = new Thread(() =>
            {                    
                lblSendStep.SetContent("Sending new titles, please wait...");

                client.SendNewTitlesToSubscriptors(booksAddedAfterDate);
            });

        threadSendNewTitles.Start();
    }
    


and the implementation of IBookServiceCallBack as an event handler:

    
    public class BookStoreNotificationHandler : IBookServiceCallback
    {
        public void NotifyClient(string message)
        {
            MainWindow.lblSendStep.SetContent(message);
        }
    }
    


* Notice that in both cases we have used the extension method SetContent in order to control the content of the components in threading, as specified in this post: WPF MainWindow Instance

The result of this mechanism is the next:





<METHOD SOFTWARE © 2016>

Monday, September 30, 2013

WCF Enable SSL

In order to include HTTPS binding to our REST Services in IIS, we have to set up the service to accept SSL Certificates

We must have installed the Certificate on IIS



Browse to the WCF Rest Service Application, click on SSL Configuration, and set up the service to accept client certificates



Now our service works under HTTPS binding, to enable both protocols, we must write two different endpoints referring the service, and stablish the behavior configuration for http and https

     
    <behavior name="ServiceBehavior">
       <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
         <serviceDebug includeExceptionDetailInFaults="false"/>
    </behavior>      
    
    <%--...--%>
    
    <bindings>
      <webHttpBinding>
        <binding name="BindHttp" crossDomainScriptAccessEnabled="true">
        </binding>      
        <binding name="BindHttps" crossDomainScriptAccessEnabled="true">
            <security mode="Transport" />
        </binding>
      </webHttpBinding>
    </bindings>
    
    <%--...--%>
    
    <services>
      <service behaviorConfiguration="ServiceBehavior" name="WCFRestService.RestService">
        <endpoint address="" behaviorConfiguration="web" binding="webHttpBinding"
          bindingConfiguration="BindHttp" contract="WCFRestService.IRestService" />      
        <endpoint address="" behaviorConfiguration="web" binding="webHttpBinding"
          bindingConfiguration="BindHttps" contract="WCFRestService.IRestService" />          
      </service>
    </services>
    


<METHOD SOFTWARE ©>

Wednesday, July 24, 2013

WCF Rest Services

When we are designing processes which expose data across multi-platform and systems, we have to consider the implementation of REST Services

REST stands for Representational State Transfer. In RESTful systems, servers expose resources using a URI, and clients access these resources using the four HTTP verbs
GET: used exclusively to retrieve data

DELETE: used for deleting resources

PUT: used to add or change a resource

POST: used to modify and update a resource
In this example, we will develop a REST Service with Xml and Json responses, using WCF, and will make the whole circuit to the call

The first step is beginning a new WCF Application. This is the implementation of the interface with the definition of the service contract

 
	namespace RestWCFService
    {
        [ServiceContract]
        public interface IRestService
        {
            [OperationContract]
            [WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Xml,
                BodyStyle = WebMessageBodyStyle.Wrapped, UriTemplate = "getXml/{id}")]
            string XmlElement(string id);

            [OperationContract]
            [WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json,
                BodyStyle = WebMessageBodyStyle.Wrapped, UriTemplate = "getJson/{id}")]
            string JsonElement(string id);
        }
    }
    


The next step is implementing the service contract

 
	public class RestService : IRestService
    {
        public string XmlElement(string atomicSymbol)
        {
            return getElement(atomicSymbol);
        }

        public string JsonElement(string atomicSymbol)
        {
            return getElement(atomicSymbol);
        }

        private string getElement(string aSymbol)
        {
            Dictionary<string, string> Elements = getElementsTable();

            if (Elements.Keys.Contains(aSymbol))
                return "the element is " + Elements[aSymbol];
            else
                return "there is no match for " + aSymbol;
        }
    }


Now we have to set up the web.config file, changing the next sections:

 
	<services>
      <service name="RestWCFService.RestService" behaviorConfiguration="ServiceBehavior">
        <endpoint binding="webHttpBinding" contract="RestWCFService.IRestService" 
            behaviorConfiguration="web">
        </endpoint>
      </service>
    </services>
    
    <behaviors>
      <serviceBehaviors>
        <behavior name="ServiceBehavior">
          <!-- To avoid disclosing metadata information, set the value below to false 
           and remove the metadata endpoint above before deployment -->
          <serviceMetadata httpGetEnabled="true"/>
          <!-- To receive exception details in faults for debugging purposes, 
           set the value below to true. Set to false before deployment 
           to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
      <endpointBehaviors>
        <behavior name="web">
          <webHttp helpEnabled="true" faultExceptionEnabled="true"/>
        </behavior>
      </endpointBehaviors>
    </behaviors>
- The 'services' section will point to our service contract definition, and the 'behaviors' section will enable the http get method

Now we publish the service and check it from the browser



http://localhost:9479/RestService.svc/getXml/O



http://localhost:9479/RestService.svc/getJson/K



To call this service from the client layer we can make use of jQuery Ajax, the code is the next

 
	function getChemical(atomicSymbol) {

        $.ajax({
            url: "http://localhost:9479/RestService.svc/getJson/" + atomicSymbol,
            type: "GET",
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            data: {},
            processdata: true,
            success: function (response) {

                var element = response.JsonElementResult;
                $('#lblElement').html(element);
            },

            error: function (e) {
                alert(e.status + ". " + e.statusText);
            }
        });
    }





<METHOD SOFTWARE © 2013>

Sunday, October 28, 2012

Calling WCF Async

When our applications call a web service, either from desktop apps or web sites, we have to keep in mind its response times

There is a mechanism for calling the web service asynchronously. Let's take the example exposed in this link, WCF Services, and configure the service reference to generate asynchronous operations



There are two different ways to achieve the process

With the next code, we are assigning a handler to the GetElementsCompleted event, so the application will work on other tasks while is waiting for the event triggers

     
private void btnGetElements_Click(object sender, EventArgs e)
{
    try
    {
        client = new ChemicalServiceClient();
        client.GetElementsCompleted += 
         new EventHandler<GetElementsCompletedEventArgs>(client_GetElementsCompleted);
        client.GetElementsAsync();
    }
    catch (FaultException<AccessFault> ex)
    {
        lblResult.Text = ex.Message + ex.Detail.ExceptionType + ex.Detail.StackTrace;
    }
}

void client_GetElementsCompleted(object sender, GetElementsCompletedEventArgs e)
{
    dgvElements.DataSource = e.Result.ToList();
    lblResult.Text = e.Result.Length.ToString() + " elements were found";
}


The second way is an asynchronous call itself, with the implementation of a callback function, it generates a separated thread to manage the call

The code is as follows

     
private void btnInsertElement_Click(object sender, EventArgs e)
{
    try
    {
        client = new ChemicalServiceClient();
        Element elemToInsert = new Element()
        {
            AtomicSymbol = txtAtomicSymbol.Text,
            Name = txtName.Text,
            LatinName = txtLatinName.Text
        };

        client.BeginInsertElement(elemToInsert, InsertAsyncCallBack, null);
    }
    catch (FaultException<AccessFault> ex)
    {
        lblResult.Text = ex.Message + ex.Detail.ExceptionType + ex.Detail.StackTrace;
    }
}

private void InsertAsyncCallBack(IAsyncResult asyncResult)
{
    if (asyncResult.IsCompleted)
    {
        string elemKey = client.EndInsertElement(asyncResult);
        lblResult.Text = elemKey + " was added correctly";
    }
}


This second way is the recommended for web scenarios, because the site will renders immediatly after the function call, instead of wait for the event fires


<METHOD SOFTWARE © 2012>

Tuesday, August 28, 2012

WCF Services

When we have to develop a process to be accessed across multiple applications and plattforms, the choice is programming a web service

WCF enables you to encapsulate processes, and expose just the methods and data neccessary to share

In this example we will design a WCF service to filter the access to a database, we will expose two methods and a class

The first step is begin a new WCF Application project

This is the interface of our service, a service dedicated to retrieve and insert data in a chemical elements table, with every Contract defined, plus one for providing information about possible exceptions to the client side

     
namespace Chemistry
{
    [ServiceContract]
    public interface IChemicalService
    {
        [OperationContract]
        [FaultContract(typeof(AccessFault))]
        Element[] GetElements();

        [OperationContract]
        [FaultContract(typeof(AccessFault))]
        string InsertElement(Element element);
    }

    [DataContract]
    public class Element
    {
        [DataMember]
        public string AtomicSymbol { get; set; }

        [DataMember]
        public string Name { get; set; }

        [DataMember]
        public string LatinName { get; set; }
    }

    [DataContract]
    public class AccessFault
    {
        [DataMember]
        public string ExceptionType { get; set; }

        [DataMember]
        public string StackTrace { get; set; }
    }
}


The code file of our service implements this interface, so we implement these methods in it

This is the code for retrieve data, the method GetElements()

     
    public Element[] GetElements()
    {
        try
        {
            SqlCommand retrieveCommand = new SqlCommand()
            {
                Connection = OpenConnection(),
                CommandType = CommandType.StoredProcedure,
                CommandText = "P_SELECT_ELEMENTS",
                CommandTimeout = 20
            };

            SqlDataReader reader = 
                retrieveCommand.ExecuteReader(CommandBehavior.CloseConnection);

            Element[] Elements = new Element[0];

            int index = 0;
            while (reader.Read())
            {
                Array.Resize<Element>(ref Elements, Elements.Length + 1);
                Element element = new Element()
                {
                    AtomicSymbol = reader[0].ToString(),
                    Name = reader[1].ToString(),
                    LatinName = reader[2].ToString()
                };
                Elements[index++] = element;
            }

            return Elements;
        }
        catch (Exception ex)
        {
            AccessFault fault = new AccessFault() 
                { ExceptionType = ex.GetType().ToString(), 
                  StackTrace = ex.StackTrace };
            throw new FaultException<AccessFault>
                (fault, new FaultReason(ex.Message));
        }
    }
    


And this is the method for inserting data

     
    public string InsertElement(Element element)
    {            
        try
        {
            SqlCommand insertCommand = new SqlCommand()
            {
                Connection = OpenConnection(),
                CommandType = CommandType.StoredProcedure,
                CommandText = "P_INSERT_ELEMENT",
                CommandTimeout = 20,
            };

            insertCommand.Parameters.AddRange(new SqlParameter[] {
                new SqlParameter("@asymbol", element.AtomicSymbol),
                new SqlParameter("@name", element.Name),
                new SqlParameter("@latinname", element.LatinName)});

            insertCommand.ExecuteNonQuery();
            insertCommand.Connection.Close();

            return element.AtomicSymbol;
        }
        catch (Exception ex)
        {
            AccessFault fault = new AccessFault() 
                { ExceptionType = ex.GetType().ToString(), 
                  StackTrace = ex.StackTrace };
            throw new FaultException<AccessFault>
                (fault, new FaultReason(ex.Message));
        }
    }
    


Now we will test the io of the service with WCF Test Client tool. Execute the service from Visual Studio and add the Url to WCF Test Client



The next step is deploying the service for its usage from different points. For this we run inetmgr, and add a new web site. Make sure your IIS is configured to allow ASP.NET v4.0 applications. You can set up this configuration with the next prompt command



After this we publish the service



Now we browse our service from IIS HostedChemicalService web site



While configuring the web site and the parameters for the service publication, we can choose any port, minding it's not busy by other application, in our case the deployment Url is

http://localhost:9789/ChemicalService.svc

The final step is calling the service layer for interacting with the database. With this purpose we create a client application, called ChemicalClient, and we add the Service Reference to the project



The code is as follows

     
    private void btnGetElements_Click(object sender, EventArgs e)
    {
        try
        {
            ChemicalServiceClient client = new ChemicalServiceClient();
            Element[] elements = client.GetElements();

            dgvElements.DataSource = elements.ToList();
            lblResult.Text = elements.Length.ToString() + " were found";
        }
        catch (FaultException<AccessFault> ex)
        {
            lblResult.Text = ex.Message + 
                ex.Detail.ExceptionType + ex.Detail.StackTrace;
        }
    }

    private void btnInsertElement_Click(object sender, EventArgs e)
    {
        try
        {
            ChemicalServiceClient client = new ChemicalServiceClient();
            Element elemToInsert = new Element()
            {
                AtomicSymbol = txtAtomicSymbol.Text,
                Name = txtName.Text,
                LatinName = txtLatinName.Text
            };

            string elemKey = client.InsertElement(elemToInsert);
            lblResult.Text = elemKey + " was added correctly";                
        }
        catch (FaultException<AccessFault> ex)
        {
            lblResult.Text = ex.Message + 
                ex.Detail.ExceptionType + ex.Detail.StackTrace;
        }
    }
    


With a correct execution, we get the next result




<METHOD SOFTWARE © 2012>