Using ErrorHandlers and singletons in WCF

by MikeHogg 19. September 2012 20:16

I had a COM wrapper that I wrote for a third party interface.  I knew I was going to use it not only in a desktop application, but also in our web application and our vendor’s web application, and also possibly further down the road in a mobile application, so I wrote a WCF web service that implemented my wrapper’s functionality rather than drop that project in multiple solutions. 

Writing the web service is easy enough.  For years in Visual Studio you can just create a WCF Project and figure out some options and add some classes.  For options you choose between NetTcp or Http binding. I have used NetTcp in intranet scenarios, but in this case I needed HttpBinding, so I could choose WS or Basic.  As WS doesn’t easily work with non .Net clients I chose Basic for this case, although I later found out this didn’t help me with my mobile client as I expected. 

The other option you usually always have to figure out is your authentication.  In this case I used basic forms authentication over https, so my service model was really simple.  I have set up services that implemented X509 client certificates, but it can be complicated and this project didn’t need that layer of security. 

 <system.serviceModel>
    <extensions>
      <behaviorExtensions>
        <add name="ErrorLogging" type="My.lib.WCF.ErrorHandlerBehavior, Mylib" />
      </behaviorExtensions>
    </extensions>
    
    <services>
      <service name="SomeSN.SomeService">
        <endpoint  binding="basicHttpBinding"
          bindingConfiguration="SSWebBinding" contract="SomeSN.ISomeService"/>
      </service>
    </services>
    <bindings>
      <basicHttpBinding>
        <binding name="SSWebBinding" sendTimeout="00:02:00">
          <security mode="TransportWithMessageCredential">
            <message clientCredentialType="UserName"/>
          </security>
        </binding>
      </basicHttpBinding>
    </bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <ErrorLogging/>
          <serviceCredentials>
            <userNameAuthentication userNamePasswordValidationMode="Custom"
              customUserNamePasswordValidatorType="Some.CustomPasswordValidator, Some" />
          </serviceCredentials>
          <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
          <serviceMetadata httpGetEnabled="false" httpsGetEnabled="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>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
If I remember right I needed to make MultipleSiteBindingsEnabled in this case for our IIS servers having other webs running. 

 

You will see at the bottom I added my ErrorHandling behavior, and my custom password validator, which was basically my password interface, in this case pointing just to the config files.

    class CustomPasswordValidator : System.IdentityModel.Selectors.UserNamePasswordValidator
    {
        public override void Validate(string userName, string password)
        {
            string[] serviceusernames = My.lib.ConfigHelper.GetAppSetting("SOME_USER", (string)null).Split(new char[]{ ';'});  //  quick solution to user mgmt assuming we only ever have two users (our website and our vendor's website) and they can share a password
            string servicepassword = My.lib.ConfigHelper.GetAppSetting("SOMe_PASS", (string)null);
            if ( !serviceusernames.Contains(userName) || String.IsNullOrEmpty(password) || !password.Equals(servicepassword) )
                throw new System.ServiceModel.FaultException("Authentication failed."); // this will just get wrapped by a messagesecurityexception an kick em out
        }
    }

 

The ErrorHandler was an interesting case, as it came up in my testing.  My COM component would fail occasionally, and it was expected to pass meaningful error messages.  I built the wrapper to fail also and pass these messages as exceptions, but when the Web Service would throw exceptions, it would just replace my meaningful messages with a general SOAP exception, and then freeze up the server to more incoming requests, which was very bad.  So I had to figure out a way to preserve those messages (easy if I turn them into messages instead of exceptions but my stack was built to use these exceptions already and this would mean lots of extra code for what I really intended to be exceptional) and not break the service, which wasn’t easy (don’t throw SOAPExceptions).  Here I just implement the Interfaces and the important part is in returning true in HandleError and in creating my MessageFault from my wrapper exceptions in ProvideFault…

    public class ErrorHandler : IErrorHandler, IServiceBehavior
    {
        public bool HandleError(Exception error)
        {
            // Logger.LogError(error);  
            return true;
        }
        public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
        {
            FaultException faultException = new FaultException(error.Message);
            MessageFault messageFault = faultException.CreateMessageFault();
            fault = Message.CreateMessage(version, messageFault, faultException.Action);
        }
        public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<System.ServiceModel.Description.ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        { 
        }
        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
            IErrorHandler errorHandler = new ErrorHandler();
            foreach (ChannelDispatcherBase channelDispatcherBase in serviceHostBase.ChannelDispatchers)
            {
                ChannelDispatcher channelDispatcher = channelDispatcherBase as ChannelDispatcher;
                channelDispatcher.ErrorHandlers.Add(errorHandler);
            }
        }
        public void Validate(System.ServiceModel.Description.ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
        { 
        }
    }
    class ErrorHandlerBehavior : System.ServiceModel.Configuration.BehaviorExtensionElement
    {
        public override Type BehaviorType
        {
            get
            {
                return typeof(ErrorHandler);
            }
        }
        protected override object CreateBehavior()
        {
            return new ErrorHandler();
        }
    }

With that I could now leave my exceptions as exceptions, and my stack would bubble up as expected, even across WCF to the client, with my meaningful messages, without freezing my channels.

The rest of my Service was simple also, a handful of OperationContracts, not even passing complex classes, except one IEnumerable<MyCustomType>.  And my Server class was also too simple to even post, since it was just a call to my COM wrapper for each web service method.  But the instantiation and initialization of the COM component and the wrapper was time intensive.  It took a few to ten seconds to create it and get it ready for use. So I wanted a way to create the wrapper once, and then use it over and over for each request, so I used a singleton pattern…

    // This class is so we can spin up one instance to handle a number of requests at once.  
    // In practice, it appears IIS will keep it in memory for a short length of time, like for several calls on one page, 
    // but it seems to dispose of it after a few minutes.... would like to investigate further...
    public sealed class MySingletonWrapper
    {
        MyWrapperClient.AdaptorClient _client; 
        static MySingletonWrapper _client = null;
        static readonly object padlock = new object();
        public static MySingletonWrapper Client
        {
            get
            {
                lock (padlock)
                {
                    if (_client == null)
                    {
                        _client = new MySingletonWrapper();
                    }
                    return _client;
                }
            }
        }
        MySingletonWrapper()
        {
            _client = GetMyWrapperClient(); 
        }
        /// <summary>
        /// initializes and prepares for transactions using properties from config file
        /// </summary>
        /// <returns></returns>
        MyWrapperClient.AdaptorClient GetMyWrapperClient(string somewireid = null, string anotherid = null, string anybodyskeyid = null)
        {
            string primary = My.lib.ConfigHelper.GetAppSetting("SS_PrimaryUrl", "https://somedomain.com/urlforsomething");
			string secondary = My.lib.ConfigHelper.GetAppSetting("SS_SecondaryUrl", "https://somedomain.com/urlforsomething");
            string whatid = My.lib.ConfigHelper.GetAppSetting("SS_MerchantId", "2323232323232323");
            if (String.IsNullOrEmpty(anotherid)) terminalid = My.lib.ConfigHelper.GetAppSetting("SS_TerminalId", "00000000001");
            if (String.IsNullOrEmpty(somewireid)) datawireid = My.lib.ConfigHelper.GetAppSetting("SS_SomeWireId", "12121212121212121212");
            if (String.IsNullOrEmpty(anybodyskeyid)) merchantkeyid = My.lib.ConfigHelper.GetAppSetting("SS_AnybodyskeyId", "2222222");
            string arefnum = My.lib.ConfigHelper.GetAppSetting("SS_ARefNum", "55555555"); 
            string whatkingkey = My.lib.ConfigHelper.GetAppSetting("SS_WhatKingKey", "88883333888833333888883333338888888333333");
            return new MyWrapperClient.AdaptorClient(primary, secondary, whatidid, anotherid, arefnum, somewireid, anybodyskeyid, WhatKingkey);
        }
        public IEnumerable<Transaction> GetTransHistory(string cardnumber, string pin)
        {
            List<Transaction> result = new List<Transaction>();
            foreach (MyWrapperClient.FSSransaction t in _client.GetTransactionHistory(cardnumber, pin)) result.Add(new Transaction(t)); }
            return result;
        }

 

This sped up my requests to sub-second times, although note where I found in IIS 7.5 there was some automatic memory management going on… something to look into for next time.

WCF vs MVC REST API

by MikeHogg 28. May 2012 15:25

 

What is this REST API that I keep hearing about?  I have been using WCF for years, but now the new buzzword is REST API for web services.

First, a good background found on this page: http://www.codeproject.com/Articles/255684/Create-and-Consume-RESTFul-Service-in-NET-Framewor

What is REST & RESTful?

Representational State Transfer (REST) is introduced by Roy Fielding on 2000; it is an architectural style of large-scale networked software that takes advantage of the technologies and protocols of the World Wide Web. REST illustrate how concentrated data objects, or resources, can be defined and addressed, stressing the easy exchange of information and scalability.

In 2000, Roy Fielding, one of the primary authors of the HTTP specification, wrote a doctoral dissertation titled Architectural Styles and the Design of Network-based Software Architectures.

REST, an architectural style for building distributed hypermedia driven applications, involves building Resource-Oriented Architecture (ROA) by defining resources that implement uniform interfaces using standard HTTP verbs (GET, POST, PUT, and DELETE), and that can be located/identified by a Uniform Resource Identifier (URI).

REST is not tied to any particular technology or platform – it’s simply a way to design things to work like the Web. People often refer to services that follow this philosophy as “RESTful services.”

My current user case asked for three clients served by one codebase- one WPF client and two web site clients, and so I figured WCF was the best way to go. But I wanted to see what new tech MS has for us...

I saw many examples of REST Controller actions in MVC, but they were using REST architecture, over Http, without typed endpoints and instant Clients from WSDL, whcih was the main reason why WCF would have been so good for my case.  WCF is so mature now that you rarely have to do more than click a few times and add some properties to a project config before you have strong typed client behaviors.  What do I get with this new REST stuff?  A lot of manual work and no strong typed objects.  It sounds like a step backwards to me.

Phil Haack agreed with me...

http://haacked.com/archive/2009/08/17/rest-for-mvc.aspx

"When your service is intended to serve multiple clients (not just your one application) or hit large scale usage, then moving to a real services layer such as WCF may be more appropriate." 

I finally found (the background I linked to above) what I was looking for in the WCF Starter Kit built on 4.0. It has strong typing, and automated client creation. It built REST on top of WCF and added some attributes you could decorate your WCF project with to work over a new protocol WebHttpEndpoint? http://www.codeproject.com/Articles/255684/Create-and-Consume-RESTFul-Service-in-NET-Framewor

This was what I was looking for, but since it built ON TOP of WCF I didn't see the point. To my point, Sam Meacham warned in Sep 2011 not to use WCF REST Starter Kit in the discussion on that page:

http://www.codeproject.com/Articles/255684/Create-and-Consume-RESTFul-Service-in-NET-Framewor?fid=1652761&df=90&mpp=50&noise=3&prof=False&sort=Position&view=Quick&fr=51#xx0xx

"The WCF REST Starter kit is abandoned, and will no longer be developed. WCF was designed to be protocol agnostic. REST services are generally built on the HTTP protocol, using all of the richness of http for your rest semantics. So WCF as it existed was actually a really bad choice for building rest services. You basically had to factor back in all of the http-ness that wcf had just factored out.

Glenn Block at Microsoft, who (with the community) developed the Managed Extensibility Framework (MEF) was reassigned to work on the WCF REST story at MS going forward. They are currently developing the WCF WEB API[^], which will be the new way to create REST services with WCF.

Also, keep in mind that REST has no service description language like WSDL or anything, so things like service location and automatic client generation don't exist. WCF certainly isn't your only chance for creating REST services in .NET. I created the RestCake? library for creating REST services based on IHttpHandler?. Also, IHttpHandler? is a very simple interface for creating REST services. A lot of people prefer to use MVC 3."

So, I conclude WCF is not going away, and is the appropriate tool for this case.  the WCF Web API that I heard rumor about appears to still be in development, coming in MVC4.

I will look at that for a future project but not this one... http://wcf.codeplex.com/wikipage?title=WCF%20HTTP

 

----

PS

Time passed, and I found myself playing with some Android development and wanted to hook up to some WCF service when I found out what is probably one of the big reasons why REST adoption is so strong- Android java libraries don't support SOAP well at all even with third party libraries! 

Tags:

Architecture | REST | WCF

Hacking up a WCF Client for a nonstandard SOAP service

by MikeHogg 12. March 2012 21:11

I set up a console shell application and framework for a team that collected data from hundreds of sources, but most of the data came from web scrapes and web services.

Setting up clients in VS usually requires just a few clicks, but when the servers are third party, and they are not using Microsoft technologies, this sometimes doesn’t work.  The VS tool will just error out with some vague message about not loading the WSDL.  Using the command line will give you some hints and sometimes you can download their WSDL to your local, and make a couple of edits, and then SvcUtil your client.

In one case in particular, even this didn’t work for me.  I was already resorting to writing custom XML requests and inspecting the responses with Fiddler to get my requests right.  I think it was some Java JBoss server, and apparently they are known for not serving a standard SOAP format.  I forget the details why...  But I knew that I could write my own DataContract and OperationContract classes and even write custom channel parsers if I had to.  They were serving lots and lots of datatypes, and methods, though, and I didn’t need but a few of them.  I had to dissect their huge wdsl file, pulling out just the Data Objects I needed and writing them by hand, instead of using the svcutil, and then running tests to find what I was missing.  I had to use XmlSerializerFormat instead of DataContractSerializer attributes for some obscure reason.

Here was my client, constructed in c# to get the requests just right:

    class MPRClient : ClientBase<IMPR>, IMPR
    {
        public MPRClient()
            : base()
        {
            System.ServiceModel.BasicHttpBinding binding = new BasicHttpBinding();
            binding.Security.Mode = BasicHttpSecurityMode.Transport;
            binding.Security.Transport.Realm = "eMPR Authentication";
            binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
            CustomBinding cbinding = new CustomBinding(binding);  // need to set keepalive=false or we get 505 after auth, this is one way
            foreach (BindingElement be in cbinding.Elements)
            {
                if (be is HttpsTransportBindingElement) ((HttpsTransportBindingElement)be).KeepAliveEnabled = false;
            }
            Endpoint.Binding = cbinding;
        }
        public queryResponse query(queryRequest request)
        {
            queryResponse result = Channel.query(request);
            return result;
        }

Here are some of my Data Classes that I figured out from the testing you will see my request and response objects, and take note of how I constructed the child objects, as arrays were the only way to get the serialization to line up just right…

    /// <summary>
    /// some's empr query web service
    /// </summary>
    [XmlSerializerFormat]
    [ServiceContract(Name = "empr", Namespace = "http://empr.some.com/mpr/xml")]
    interface Impr
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="queryRequest">
        /// query takes two parms- CompanyName(LSE) and Day
        /// </param>
        /// <returns>
        /// sample data you can get from this service:
        /// <PeakLoadSummary Day="2012-01-23">
        ///     <LSE>NEV</LSE>
        ///     <ZoneName>AECO</ZoneName>
        ///     <AreaName>AECO</AreaName>
        ///     <UploadedMW>70.4</UploadedMW>
        ///     <ObligationPeakLoadMW>70.064</ObligationPeakLoadMW>
        ///     <ScalingFactor>0.99523</ScalingFactor>
        ///     </PeakLoadSummary>
        /// </PeakLoadSummarySet>
        /// </returns>
        [XmlSerializerFormat]
        [OperationContract(Action = "/mpr/xml/query")]
        queryResponse query(queryRequest queryRequest);
    }
    [MessageContract(WrapperName = "QueryRequest", WrapperNamespace = "http://empr.some.com/mpr/xml", IsWrapped = true)]
    [XmlSerializerFormat]
    public class queryRequest
    {
        [MessageBodyMember(Namespace = "http://empr.some.com/mpr/xml", Order = 0)]
        [System.Xml.Serialization.XmlElement("QueryPeakLoadSummary")]
        QueryPeakLoadSummary[] Items;
        public queryRequest() { }
        public queryRequest(QueryPeakLoadSummary[] items)
        {
            Items = items;
        }
    }
    [XmlSerializerFormat]
    [System.Xml.Serialization.XmlType(AnonymousType = true, Namespace = "http://empr.some.com/mpr/xml")]
    public class QueryPeakLoadSummary
    {
        [System.Xml.Serialization.XmlAttribute]
        public string CompanyName;
        [System.Xml.Serialization.XmlAttribute]
        public string Day;
        public QueryPeakLoadSummary() { }
    }
    [MessageContract(WrapperName = "QueryResponse", WrapperNamespace = "http://empr.some.com/mpr/xml", IsWrapped = true)]
    [XmlSerializerFormat]
    public class queryResponse
    {
        [MessageBodyMember(Namespace = "http://empr.some.com/mpr/xml", Order = 0)]
        [System.Xml.Serialization.XmlElement("PeakLoadSummarySet")]
        public PeakLoadSummarySet[] Items;
        public queryResponse() { }
        public queryResponse(PeakLoadSummarySet[] Items)
        {
            this.Items = Items;
        }
    }
    [XmlSerializerFormat]
    [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://empr.some.com/mpr/xml")]
    public class PeakLoadSummarySet
    {
        [System.Xml.Serialization.XmlElement("PeakLoadSummary", Order = 0)]
        public PeakLoadSummary[] PeakLoadSummary;
    }
    [XmlSerializerFormat]
    [System.Xml.Serialization.XmlType(AnonymousType = true, Namespace = "http://empr.some.com/mpr/xml")]
    public class PeakLoadSummary
    {
        [System.Xml.Serialization.XmlElement(Order = 0)]
        public string LSE;
        [System.Xml.Serialization.XmlElement(Order = 1)]
        public string ZoneName;
        [System.Xml.Serialization.XmlElement(Order = 2)]
        public string AreaName;
        [System.Xml.Serialization.XmlElement(Order = 3)]
        public string UploadedMW;
        [System.Xml.Serialization.XmlElement(Order = 4)]
        public string ObligationPeakLoadMW;
        [System.Xml.Serialization.XmlElement(Order = 5)]
        public double ScalingFactor;
        [System.Xml.Serialization.XmlAttribute]
        public DateTime Day;
        public PeakLoadSummary() { }
    }

 

My client config was just a one line endpoint, since the options to set the keepaliveenabled were not available in the config, and I put it in the c# initialization:

  <system.serviceModel>
    <bindings>
      
      <netTcpBinding> 
        <binding name="pooledInstanceNetTcpEP_something else
      </netTcpBinding>
      
      <basicHttpBinding>
        <binding name="OperatorInterfaceSoap" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true">
          <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
          <security mode="Transport">
            <transport clientCredentialType="Basic"/> 
          </security>              
        </binding>
          
      </basicHttpBinding>
 
    </bindings>
 
    
    <client> 
      
      <endpoint address="net.tcp://Tosomethingelse
        </identity>
      </endpoint>
      <endpoint address="https://b2bsomething else
      </endpoint>
      <endpoint address="https://rpm.pjm.com/erpm/services/query"  binding="basicHttpBinding"
                contract="jobs.IRPM" >
      </endpoint>
 
      
    </client>     
  </system.serviceModel>

And then I could write business code just like normal:

        private List<queryResponse> GetResponses(List<Account> accounts, DateTime date)
        {
            List<queryResponse> result = new List<queryResponse>();
            foreach (Account account in accounts)
            {
                MPRClient r = new MPRClient();
                r.ClientCredentials.UserName.UserName = account.Username;
                r.ClientCredentials.UserName.Password = account.Password;
                result.Add(r.query(new queryRequest(
                    new QueryPeakLoadSummary[] { 
                         new QueryPeakLoadSummary{ CompanyName = account.Company, Day = date.ToString("yyyy-MM-dd") }
                     }
                    )));  // day must be 00 digits
            }
            return result;
        }

Tags:

WCF

Streaming 100 megabyte csv files with WCF

by MikeHogg 21. February 2012 20:35

WCF is very configurable, but that is also the thing that I like least about it.  Often I have a project, and a need, and I’m in WCF documentation, and researching how to do exactly what I want, and I get my config just right, tweaked and tested and it works perfectly, but I never learn a new pattern or algorithm.  They are just config options.  Here is a case where I had to play with the buffer limits to be able to stream very large files, but there are more than a few options related to buffer size and so you have to know exactly which ones work for your case.

Here is my client endpoint.  You will see I am using NetTcp.  I’m in an intranet environment.  I added settings for TransferMode(Stream), ReceiveTimeout(ten minutes), also SendTimeout, as the client also uploaded large files too, and MaxReceivedMessageSize(250MB)

 <system.serviceModel>
        <bindings>
            <netTcpBinding>
                <binding name="NetTcpBindingEndpoint" closeTimeout="00:01:00"
                    openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:10:00"
                    transactionFlow="false" transferMode="StreamedResponse" transactionProtocol="OleTransactions"
                    hostNameComparisonMode="StrongWildcard" listenBacklog="10"
                    maxBufferPoolSize="524288" maxBufferSize="65536" maxConnections="10"
                    maxReceivedMessageSize="250000000">
                    <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                        maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                    <security mode="Transport">
                        <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" />
                        <message clientCredentialType="Windows" />
                    </security>
                </binding>
            </netTcpBinding>
            <wsHttpBinding>
                <binding name="WSHttpBinding_AnotherClient
                </binding>
            </wsHttpBinding>
        </bindings>
        <client>  
           <endpoint address="anotherendpoint
            </endpoint>
          <endpoint address="net.tcp://somedevserver:8445/SOME_DATA_SERVICE"
                binding="netTcpBinding" bindingConfiguration="NetTcpBindingEndpoint"
                contract="DataServiceReference.IDataService" name="NetTcpBindingEndpoint">
                <identity>
                    <dns value="localhost" />
                </identity>
            </endpoint>
        </client> 
    </system.serviceModel>

You will see similar options in my service config:

 <system.serviceModel>
        <behaviors>
            <serviceBehaviors>
                <behavior name="WindowsService.DataServiceBehavior">
                    <serviceMetadata httpGetEnabled="false" />
                    <serviceDebug includeExceptionDetailInFaults="false" />
                </behavior>
            </serviceBehaviors>
        </behaviors>
      <bindings>
        <netTcpBinding>
          <binding name="NetTcpBinding" maxReceivedMessageSize="250000000" transferMode="StreamedResponse"
                    receiveTimeout="00:10:00" sendTimeout="00:10:00">
            <security mode="Transport">
              <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign"/>
              <message clientCredentialType="Windows"/>
            </security>
          </binding>
        </netTcpBinding>
      </bindings>
        <services>
            <service behaviorConfiguration="WindowsService.DataServiceBehavior"
                name="SOME_DATA_SERVICE.DataService">
                <endpoint address="" binding="netTcpBinding" bindingConfiguration="NetTcpBinding"
                    name="NetTcpBindingEndpoint" contract="SOME_DATA_SERVICE.IDataService">                  
                    <identity>
                        <dns value="localhost" />
                    </identity>
                </endpoint>
                <endpoint address="mex" binding="mexTcpBinding" bindingConfiguration=""
                    name="MexTcpBindingEndpoint" contract="IMetadataExchange" />
                <host>
                    <baseAddresses>
                        <add baseAddress="net.tcp://localhost:8445/SOME_DATA_SERVICE" />
                    </baseAddresses>
                </host>
              
            </service>
          
        </services>
    </system.serviceModel>
  <!-- added this to see trace file -->
  <!--<system.diagnostics>
    <sources>
      <source name="System.ServiceModel"
              switchValue="Information"
              propagateActivity="true">
        <listeners>
          <add name="ServiceModelTraceListener"
               type="System.Diagnostics.XmlWriterTraceListener, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
               initializeData="wcf-traces.svclog"/>
        </listeners>
      </source>
    </sources>
  </system.diagnostics>-->

 

And the c# code to stream:

        private System.IO.MemoryStream GetCSVStream(System.Data.Common.DbDataReader dr)
        {
            Initialize();
            try
            {
                System.IO.MemoryStream ms = new System.IO.MemoryStream();
                System.IO.StreamWriter sw = new System.IO.StreamWriter(ms);
                System.Data.DataTable header = dr.GetSchemaTable();
                foreach (System.Data.DataRow r in header.Rows)
                {
                    string column = r["ColumnName"].ToString();
                    if (column == "ID") column = "id";
                    sw.Write(column);
                    if (header.Rows.IndexOf(r) < header.Rows.Count - 1) sw.Write("|");
                }
                sw.Write(sw.NewLine); sw.Flush();
                while (dr.Read())
                {
                    sw.Write(dr.GetValue(0).ToString());
                    for( int x = 1; x < dr.FieldCount; x++ )
                    {
                        sw.Write("|");
                        sw.Write(dr.GetValue(x).ToString());
                    }
                    sw.Write(sw.NewLine); sw.Flush();
                } 
                ms.Position = 0;
                return ms;
            }
            catch (Exception ex)
            {
                LogError(ex, APPNAME);
                return null;
            }
        } 
and that’s it!

Tags:

WCF

About Mike Hogg

Mike Hogg is a c# developer in Brooklyn.

More Here

Favorite Books

This book had the most influence on my coding style. It drastically changed the way I write code and turned me on to test driven development even if I don't always use it. It made me write clearer, functional-style code using more principles such as DRY, encapsulation, single responsibility, and more. amazon.com

This book opened my eyes to a methodical and systematic approach to upgrading legacy codebases step by step. Incrementally transforming code blocks into testable code before making improvements. amazon.com

More Here