WCF: Basic HTTP Binding (Source Code & Housekeeping)

The previous post, which concerned WCF and the basic HTTP binding, was long and windy. Today we'll get down to brass tacks.

First, we'll add logging to the service. After that, we'll just put all the source code out there so it's easy to see everything without my jabber getting in the way.

Logging with log4net
First, add a reference to log4net. I typically go through NuGet:



Once that's done, I update the Web.config file:

<?xml version="1.0"?>
<configuration>
  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
  </configSections>
  
  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
  </appSettings>
  
  <system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5"/>
  </system.web>
  
  <system.serviceModel>
    <services>
      <service name="MyWcfService.MyService" behaviorConfiguration="BASIC">
        <endpoint
          address="BASIC"
          binding="basicHttpBinding"
          contract="MyWcfService.IMyService"/>
        <endpoint
          address="MEX"
          binding="mexHttpBinding"
          contract="IMetadataExchange"/>
      </service>
    </services>
    
    <behaviors>
      <serviceBehaviors>
        <behavior name="BASIC">
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="true"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
  </system.serviceModel>
  
  
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
    <!--
        To browse web app root directory during debugging, set the value below to true.
        Set to false before deployment to avoid disclosing web app folder information.
      -->
    <directoryBrowse enabled="true"/>
  </system.webServer>

  <log4net>
    <appender name="FileAppender" type="log4net.Appender.FileAppender">
      <file value="MyWcfService.log" />
      <appendToFile value="true" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
      </layout>
    </appender>
    <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender" >
      <layout type="log4net.Layout.PatternLayout">
        <param name="Header" value="[Header]\r\n" />
        <param name="Footer" value="[Footer]\r\n" />
        <param name="ConversionPattern" value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
      </layout>
    </appender>
    <!--
    <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
      <file value="Log4NetApplicationRollingLog.log" />
      <appendToFile value="true" />
      <rollingStyle value="Size" />
      <maxSizeRollBackups value="10" />
      <maximumFileSize value="1MB" />
      <staticLogFileName value="true" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %level %logger - %message%newline" />
      </layout>
    </appender>
    -->
    <root>
      <level value="ALL" />
      <appender-ref ref="FileAppender" />
      <appender-ref ref="ConsoleAppender"/>
      <!--<appender-ref ref="RollingFileAppender"/>-->
    </root>
  </log4net>
</configuration>


The updates are highlighted.

Next, update the service host file to use log4net:

[assembly: log4net.Config.XmlConfigurator(Watch = true)]

namespace MyWcfService
{
    public class MyService : IMyService
    {
        private static readonly log4net.ILog Logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        /// <summary>
        /// 
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public string GetData(int value)
        {
            Logger.Debug("Entering GetData()...");
            // do some work
            Logger.Debug("LeavingGetData()...");
            return string.Format("You entered: {0}", value);
        }
    }
}

Since there's no console window for our service, yet, the only way to view our log is to open it directly:



Logging isn't so important now but will be later. And, it's especially neat when you do self-hosting via a console application and can watch the service's activity scroll by in real time.
Complete Source Code for Service
Web.config
See above.

MyService.svc.cs
See above.

IMyService.cs
using System.ServiceModel;

namespace MyWcfService
{
    [ServiceContract]
    public interface IMyService
    {
        [OperationContract]
        string GetData(int value);
    }
}


Complete Source Code for Client
App.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
  </configSections>
  
  <startup> 
      <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
  </startup>

  <system.serviceModel>
        <bindings>
            <basicHttpBinding>
                <binding name="BasicHttpBinding_IMyService" />
            </basicHttpBinding>
        </bindings>
        <client>
            <endpoint 
              address="http://localhost:2374/MyService.svc/BASIC"
              binding="basicHttpBinding" 
              bindingConfiguration="BasicHttpBinding_IMyService"
              contract="IMyService" 
              name="BasicHttpBinding_IMyService" />
        </client>
    </system.serviceModel>
  
  <log4net>
    <appender name="FileAppender" type="log4net.Appender.FileAppender">
      <file value="Log4NetApplicationLog.log" />
      <appendToFile value="true" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
      </layout>
    </appender>
    <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender" >
      <layout type="log4net.Layout.PatternLayout">
        <param name="Header" value="[Header]\r\n" />
        <param name="Footer" value="[Footer]\r\n" />
        <param name="ConversionPattern" value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
      </layout>
    </appender>
    <!--
    <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
      <file value="Log4NetApplicationRollingLog.log" />
      <appendToFile value="true" />
      <rollingStyle value="Size" />
      <maxSizeRollBackups value="10" />
      <maximumFileSize value="1MB" />
      <staticLogFileName value="true" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %level %logger - %message%newline" />
      </layout>
    </appender>
    -->
    <root>
      <level value="ALL" />
      <appender-ref ref="FileAppender" />
      <appender-ref ref="ConsoleAppender"/>
      <!--<appender-ref ref="RollingFileAppender"/>-->
    </root>
  </log4net>
</configuration>

Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using log4net;

[assembly: log4net.Config.XmlConfigurator(Watch = true)]

namespace MyWcfService.Client
{
    class Program
    {
        private static readonly log4net.ILog Logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        static void Main(string[] args)
        {
            Logger.Info("Starting Main()...");

            try
            {
                // establish a client
                var client = new MyServiceClient();

                // get the heck outta Dodge
                Console.WriteLine("Press any key to get data.");
                Console.ReadKey();
                string response = client.GetData(10);
                Console.WriteLine(response);

                // always close the client.
                client.Close();
            }
            catch (Exception ex)
            {
                Logger.Error("Exception: " + ex.Message);
                Exception innerException = ex.InnerException;
                Logger.Error("Inner Exception: " + innerException.Message);
            }

            // get the heck outta Dodge
            Console.WriteLine("Press any key to exit.");
            Console.ReadKey();

            Logger.Info("Ending Main()");

            Environment.Exit(0);
        }
    }
}

MyService.cs (the proxy)
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.18444
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------



[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(ConfigurationName="IMyService")]
public interface IMyService
{
    
    [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IMyService/GetData", ReplyAction="http://tempuri.org/IMyService/GetDataResponse")]
    string GetData(int value);
    
    [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IMyService/GetData", ReplyAction="http://tempuri.org/IMyService/GetDataResponse")]
    System.Threading.Tasks.Task<string> GetDataAsync(int value);
}

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
public interface IMyServiceChannel : IMyService, System.ServiceModel.IClientChannel
{
}

[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
public partial class MyServiceClient : System.ServiceModel.ClientBase<IMyService>, IMyService
{
    
    public MyServiceClient()
    {
    }
    
    public MyServiceClient(string endpointConfigurationName) : 
            base(endpointConfigurationName)
    {
    }
    
    public MyServiceClient(string endpointConfigurationName, string remoteAddress) : 
            base(endpointConfigurationName, remoteAddress)
    {
    }
    
    public MyServiceClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) : 
            base(endpointConfigurationName, remoteAddress)
    {
    }
    
    public MyServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : 
            base(binding, remoteAddress)
    {
    }
    
    public string GetData(int value)
    {
        return base.Channel.GetData(value);
    }
    
    public System.Threading.Tasks.Task<string> GetDataAsync(int value)
    {
        return base.Channel.GetDataAsync(value);
    }
}

Where to Go From Here
Next, we'll create a console application to host our WCF service and, after that, move on to the other bindings.





Comments

Popular posts from this blog

Using Reference Aliases

List of Visual Studio Keyboard Shortcuts