Musings

A random collection

Archive for the ‘dotNET’ Category

.NET: Bulk Inserts

Using Entity Framework and want to do a bulk copy to SQL Server database:

using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Transactions;

string bulkCopyConnStr = ConfigurationManager.ConnectionStrings["BulkOperations"].ConnectionString;

List<trade> trades = new List<trade>();
foreach (OptionTO inst in instruments)
{
  if (inst.value != null)
  {
    var newTrade = new trade
    {
      bookid = inst.bookId,
      strike = inst.K,
      impliedVol = inst.sigma
    };
    trades.Add(newTrade);
  }
}

using (SqlConnection conn = new SqlConnection(bulkCopyConnStr))
{
  conn.Open();
  using (var tx = conn.BeginTransaction())
  {
    SqlBulkCopy bc = new SqlBulkCopy(conn,
      SqlBulkCopyOptions.CheckConstraints |
      SqlBulkCopyOptions.FireTriggers |
      SqlBulkCopyOptions.KeepNulls, tx);
    bc.BatchSize = 10000;
    bc.DestinationTableName = "trade";
    bc.WriteToServer(trades.AsDataReader());
    tx.Commit();
  }
  conn.Close();
}

Note: this code uses EntityDataReader class for trades.AsDataReader() call.

You will ofcourse need to put this in your app.config

<connectionStrings>
  <add name="BulkOperations" connectionString="data source=DBSERVER;Initial Catalog=DBINSTANCE;user id=DBUSER;password=DBPASSWD;MultipleActiveResultSets=True;persist security info=False;packet size=4096" providerName="" />
</connectionStrings>
Advertisements

Written by curious

July 6, 2011 at 9:13 am

Posted in dotNET

.NET: C# to Excel

Example of adding a row to an Excel Spreadsheet with C#

public static bool AddARow(string filename, Fields values)
{
	bool success = false;
	Microsoft.Office.Interop.Excel.Workbook workbook = null;
	try
	{
		Microsoft.Office.Interop.Excel.Application excelApp = new Microsoft.Office.Interop.Excel.Application();
		excelApp.Interactive = false;
		excelApp.Visible = false;
		excelApp.UserControl = false;
		excelApp.DisplayAlerts = false;
		excelApp.ScreenUpdating = false;

		workbook = excelApp.Workbooks.Open(
				filename,
				Type.Missing,               /* UpdateLinks */
				Type.Missing,               /* ReadOnly    */
				Type.Missing,               /* Format    */
				Type.Missing,               /* Password    */
				Type.Missing,               /* WriteResPassword    */
				Type.Missing,               /* IgnoreReadOnlyRecommended    */
				Type.Missing,               /* Origin    */
				Type.Missing,               /* Delimiter    */
				Type.Missing,               /* Editable    */
				Type.Missing,               /* Notify    */
				Type.Missing,               /* Converter    */
				Type.Missing,               /* AddToMru    */
				Type.Missing,               /* Local    */
				Type.Missing                /* CorruptLoad    */
			);

		int numSheets = workbook.Sheets.Count;
		Microsoft.Office.Interop.Excel.Worksheet worksheet = workbook.Sheets[1];

		Microsoft.Office.Interop.Excel.Range range = worksheet.UsedRange;
		int x = range.Rows.Count;

		System.Console.WriteLine(x);

		string id = range.get_Range("A"+x).Text;
		
		int newId = int.Parse(id)+1;
		++x;

		Microsoft.Office.Interop.Excel.Range r = worksheet.get_Range("A"+x + ":X" + x);
		object[] excelValues = {
				newId,
			};
		r.Value2 = excelValues;

		if (!workbook.Saved)
		{
			workbook.SaveAs(filename);
		}
		workbook.Close();
			// object SaveChanges = Type.Missing,
			// object Filename = Type.Missing,
			// object RouteWorkbook = Type.Missing

		success = true;
	}
	catch (System.Exception e)
	{
		Console.WriteLine("Error: " + e.Message);
	}
	finally
	{
		if (workbook != null)
			System.Runtime.InteropServices.Marshal.ReleaseComObject(workbook);
	}

	return success;
}

Written by curious

February 11, 2011 at 4:14 pm

Posted in dotNET

.NET: Trace Logging to Console in C# Applications

In your code put the Trace messages at strategic places

  System.Diagnostics.Trace.TraceInformation(string message);

  System.Diagnostics.Debug.WriteLine("a debug message");

  // this is convenient
  System.Diagnostics.Debug.WriteLineIf(iUnitQty > 50, "This message WILL appear");

  // can event direct log messages to wherever
  TextWriterTraceListener tr1 = new TextWriterTraceListener(System.Console.Out);
  Debug.Listeners.Add(tr1);
        
  TextWriterTraceListener tr2 = new TextWriterTraceListener(System.IO.File.CreateText("Output.txt"));
  Debug.Listeners.Add(tr2);

  TextWriterTraceListener myCreator = new TextWriterTraceListener(System.Console.Out);
  Trace.Listeners.Add(myCreator);

Note: Debug messages will not appear in Release builds, they will be enabled only in Debug builds. Trace messages however will show up in Release & Debug builds.

Stick the following XML in your app.config in “<configuration>” section

  <system.diagnostics>
    <trace autoflush="true" indentsize="4">
      <listeners>
        <add name="configConsoleListener"
             type="System.Diagnostics.ConsoleTraceListener" />
      </listeners>
    </trace>
  </system.diagnostics>

Or

  <system.diagnostics>
    <trace autoflush="true" indentsize="4">
      <listeners>
        <add initializeData="...\console-host.svclog" type="System.Diagnostics.XmlWriterTraceListener" name="traceListener">
            <filter type=""/>
        </add>

        <add name="FileListener"
                 type="System.Diagnostics.TextWriterTraceListener"
                 initializeData=".\blabla-trace.txt" /> 
      </listeners>
    </trace>
  </system.diagnostics>

To add a timestamp or a datetime add TraceOutputOption to your config file:

        <add name="FileListener"
                 type="System.Diagnostics.TextWriterTraceListener"
                 initializeData=".\blabla-trace.txt"
                 traceOuputOptions="DateTime"       <!-- Timestamp|HostName|ThreadID|... -->
                 /> 

Written by curious

January 27, 2011 at 10:24 am

Posted in dotNET

.NET: C# Tips

  1. Initializing objects
    public class Point
    {
    	public int X { get; set; }
    	public int Y { get; set; }
    }
    Point a = new Point { X = 0, Y = 1 };
    
    public class Rectangle
    {
    	public Point p1 { get; set; }
    	public Point p2 { get; set; }
    }
    Rectangle r = new Rectangle {
    	p1 = { X = 0, Y = 1 },
    	p2 = { X = 2, Y = 3 }
    };
    
  2. Array Initializer
    int[,] a = new int[,] { {1,2}, {3,4}, {5,6} };
    
  3. Print current time
    DateTime currentSystemTime = DateTime.Now;
    Console.WriteLine(currentSystemTime);
    
  4. Measure time difference
    /* Read the initial time. */
    DateTime startTime = DateTime.Now;
    Console.WriteLine(startTime);
    
    /* Do something that takes up some time. For example sleep for 1.7 seconds. */
    Thread.Sleep(1700);
    
    /* Read the end time. */
    DateTime stopTime = DateTime.Now;
    Console.WriteLine(stopTime);
    
    /* Compute the duration between the initial and the end time. */
    TimeSpan duration = stopTime - startTime;
    Console.WriteLine(duration);
    
    Console.WriteLine("Total time in msecs: " + duration.TotalMilliseconds);
    
  5. Use StopWatch
    [DllImport("kernel32.dll")]
    public static extern bool QueryPerformanceCounter(out long value);
    
    using System.Diagnostics;
    Stopwatch sw = new Stopwatch();
    sw.Start();
    // sw = new StopWatch.StartNew();
    
    Thread.Sleep(1000);
    
    sw.Stop();
    
    sw.ElapsedMilliseconds
    sw.ElapsedTicks * sw.Frequency
    
    

Written by curious

January 5, 2011 at 12:28 pm

Posted in dotNET

.NET: WCF Service Logging

To enable trace logging in WCF service do the following:

  1. Hint: May use C:\Program Files\Microsoft SDKs\Windows\v6.0,v6.0A,v7.0\Bin\svcconfigeditor.exe to edit Config file
  2. Define Trace Sources in Config File
    1. System.ServiceModel – Logs all stages of WCF processing, whenever configuration is read, a message is processed in transport, security processing, a message is dispatched in user code, and so on
    2. System.ServiceModel.MessageLogging – Logs all messages that flow through the system
    3. System.IdentityModel
    4. System.ServiceModel.Activation
    5. System.IO.Log – Logging for the .NET Framework interface to the Common Log File System
    6. System.Runtime.Serialization – Logs when objects are read or written
  3. Define Trace Listeners to Consume Traces for each source, example: System.Diagnostics.XmlWriterTraceListener . You can have shared listeners for all/multiple sources, and you can have more than one listeners for each source.
  4. Configure Activity Tracing and Propagation
  5. Example:
    <configuration>
      <system.serviceModel>
        <diagnostics performanceCounters="All">
            <messageLogging maxMessagesToLog="30000" logEntireMessage="true" logMessagesAtServiceLevel="true" logMalformedMessages="true" logMessagesAtTransportLevel="true">
            </messageLogging>
        </diagnostics>
      </system.serviceModel>
    
      <system.diagnostics>
        <sources>
          <source name="System.ServiceModel" switchValue="Verbose, ActivityTracing">
            <listeners>
              <add name="xml"/>
            </listeners>
          </source>
          <source name="System.ServiceModel.MessageLogging" switchValue="Verbose">
            <listeners>
              <add name="xml"/>
            </listeners>
          </source>
        </sources>
        <sharedListeners>
          <add name="xml" type="System.Diagnostics.XmlWriterTraceListener" initializeData="e2eTraceTest.e2e"/>
        </sharedListeners>
        <trace autoflush="true"/>
      </system.diagnostics>
    
      <system.diagnostics>
        <sources>
          <source name="System.ServiceModel" 
                      switchValue="Information, ActivityTracing"
                      propagateActivity="true">
            <listeners>
              <add name="traceListener" 
                      type="System.Diagnostics.XmlWriterTraceListener" 
                      initializeData= "c:\log\Traces.svclog" />
            </listeners>
          </source>
        </sources>
      </system.diagnostics>
    </configuration>
    
  6. C:\Program Files\Microsoft SDKs\Windows\v7.0A\bin\svctraceviewer.exe

Your own logging in WCF

  1. Use System.Diagnostics.TraceSource to create a trace source for your application/module
  2. Start logging with traceSource.TraceEvent() calls
  3. Enable logging for your module in config file
  4. Let us see an example:
    private System.Diagnostics.TraceSource ts;
    ...
    ts = new System.Diagnostics.TraceSource("MyOwnServiceTraceSource");
    ...
    ts.TraceEvent(System.Diagnostics.TraceEventType.Information, 1, "Voila!");
    	
  5. Example of config file changes:
    <configuration>
        <system.diagnostics>
            <sources>
              <source name="MyOwnServiceTraceSource" switchValue="Verbose, ActivityTracing">
                <listeners>
                  <add name="xml"/>
                </listeners>
              </source>
            </sources>
            <sharedListeners>
                <add name="xml" type="System.Diagnostics.XmlWriterTraceListener" initializeData="myownlogs.xml"/>
            </sharedListeners>
            <trace autoflush="true"/>
        </system.diagnostics>
    </configuration>
    	

Written by curious

November 30, 2010 at 10:56 am

Posted in dotNET

.NET: WCF Service 101

Tidbits

  • .NET Namespace for WCF Attributes: System.ServiceModel – Remember to add a reference to it in your project (if it is not already there).

Steps for writing a WCF Service

  1. Define the contract – a WCF attribute decorated C# class. Provide its implementation
  2. Define an endpoint –
  3. Host the service
using System;
using System.ServiceModel;

namespace FooBar
{
    [ServiceContract]
    public interface IMyService
    {
        [OperationContract]
        double GetValue(string id);
    }

    public class MyServiceImpl : IMyService
    {
        public double GetValue(string id)
        {
            return 20.21;
        }
    }

    public class Program
    {
        public static void Main(string[] args)
        {
            // Create a ServiceHost
            ServiceHost host = new ServiceHost(typeof(MyServiceImpl), new Uri("http://localhost:8001/FooBar"));

            // Make an Endpoint
            host.AddServiceEndpoint(typeof(IMyService), new BasicHttpBinding(), "");

            // Open ServiceHost
            host.Open();

            Console.WriteLine("Are you happy? Is that enough?");
            Console.ReadLine();

            host.Close();
        }
    }
}

Client code

using System;
using System.ServiceModel;

namespace FooBar
{
    [ServiceContract]
    public interface IMyService
    {
        [OperationContract]
        double GetValue(string id);
    }

    public class Client
    {
        public static void Main(string[] args)
        {
            ChannelFactory<IMyService> factory =
                new ChannelFactory<IMyService>(
                    new BasicHttpBinding(),
                    new EndpointAddress("http://localhost:8001/FooBar")
                    );
            IMyService client = factory.CreateChannel();

            double p = client.GetValue("HelloWorld");
            Console.WriteLine("Value = " + p);
        }
    }
}

How about making it configurable?

using System;
using System.ServiceModel;

namespace FooBar
{
    [ServiceContract]
    public interface IMyService
    {
        [OperationContract]
        double GetValue(string id);
    }

    public class MyServiceImpl : IMyService
    {
        public double GetValue(string id)
        {
            return 20.21;
        }
    }

    public class Program
    {
        public static void Main(string[] args)
        {
            // Create a ServiceHost
            using (ServiceHost host = new ServiceHost(typeof(MyServiceImpl)))
            {
                try
                {
                    host.Open();

                    Console.WriteLine("Here you go. Let me know when it is enough.");
                    Console.ReadLine();
                    host.Close();
                }
                catch (TimeoutException timeProblem)
                {
                    Console.WriteLine(timeProblem.Message);
                }
                catch (CommunicationException commProblem)
                {
                    Console.WriteLine(commProblem.Message);
                }
            }
        }
    }
}

The config is:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <services>
      <service name="FooBar.MyServiceImpl">
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8001/FooBar"/>
          </baseAddresses>
        </host>

        <endpoint address=""
                  binding="basicHttpBinding"
                  contract="FooBar.IMyService" >          
        </endpoint>
      </service>
    </services>
  </system.serviceModel>
</configuration>

Enable MEX Endpoint

Lets do it programmatically:

        public static void Main(string[] args)
        {
            // Create a ServiceHost
            ServiceHost host = new ServiceHost(typeof(MyServiceImpl), new Uri("http://localhost:8001/FooBar"));

            // Make an Endpoint
            host.AddServiceEndpoint(typeof(IMyService), new BasicHttpBinding(), "");
            host.AddServiceEndpoint(typeof(IMetadataExchang), MetadataExchangeBindings.CreateMexHttpBinding(), "mex");

            // Add Metadata Behavior
            ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();
            behavior.HttpGetEnabld = true;
            host.Description.Behaviors.Add(behavior);

            // Open ServiceHost
            host.Open();

            Console.WriteLine("Are you happy? Is that enough?");
            Console.ReadLine();

            host.Close();
        }

Or do it in config file

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <services>
      <service name="FooBar.MyServiceImpl"
                      behaviorConfiguration="myMexBehavior"
                      >
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8001/FooBar"/>
          </baseAddresses>
        </host>

        <endpoint address=""
                  binding="basicHttpBinding"
                  contract="FooBar.IMyService" />
        <endpoint address="mex"
                  binding="mexHttpBinding"
                  contract="IMetadataExchange" />
      </service>
    </services>

    <behaviors>
      <serviceBehaviors>
        <behavior name="myMexBehavior">
          <serviceMetadata httpGetEnabled="True" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>

Client using SVUTIL

  1. Start the Service if it is not already running
  2. Run SVCUTIL to create config and proxy class and add them to the project
  3. Or “Add Service Reference” in Visual Studio 2008
    • Select Project and right click, choose “Add Service Reference …”
    • Fill: Address = “http://localhost:8001/FooBar&#8221;, and click on “Go”
    • Enter “FooBar” in namespace
    • It will create the following app.config file
      <?xml version="1.0" encoding="utf-8" ?>
      <configuration>
          <system.serviceModel>
              <bindings>
                  <basicHttpBinding>
                      <binding name="BasicHttpBinding_IMyService" closeTimeout="00:01:00"
                          openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
                          allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
                          maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
                          messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
                          useDefaultWebProxy="true">
                          <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                              maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                          <security mode="None">
                              <transport clientCredentialType="None" proxyCredentialType="None"
                                  realm="" />
                              <message clientCredentialType="UserName" algorithmSuite="Default" />
                          </security>
                      </binding>
                  </basicHttpBinding>
              </bindings>
              <client>
                  <endpoint address="http://localhost:8001/FooBar" binding="basicHttpBinding"
                      bindingConfiguration="BasicHttpBinding_IMyService1" contract="FooBar.IMyService"
                      name="BasicHttpBinding_IMyService" />
              </client>
          </system.serviceModel>
      </configuration>
      
    • As part of the service reference it creates a proxy client, FooBar.MyServiceClient, that you can use in your client code
              public static void Main(string[] args)
              {
                  FooBar.MyServiceClient client = new FooBar.MyServiceClient();
                  double p = client.GetValue("HelloWorld");
                  Console.WriteLine("Value = " + p);
                  client.Close();
              }
      

Running SVCUTIL on a DLL

"C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\svcutil.EXE" ServiceContract.dll DataContract.dll /directory:tmp
"C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\svcutil.EXE" tmp\*.wsdl tmp\*.xsd /directory:src /language:C# /noConfig /o:ClientProxy.cs /tcv:Version35 /namespace:*,MyTestNamespace
"C:\Program Files\Microsoft SDKs\Windows\v7.0A\bin\NETFX 4.0 Tools\svcutil.EXE" ServiceContract.dll /directory:tmp
"C:\Program Files\Microsoft SDKs\Windows\v7.0A\bin\NETFX 4.0 Tools\svcutil.EXE" *.wsdl *.xsd /language:C# /noConfig /o:ClientProxy.cs /namespace:*,MyProxyNS.Test

Editing help for App.Config

"C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\SvcConfigEditor.exe"
"C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\SvcTraceViewer.exe"

Some quick notes

  1. WCF included in .NET Framework 3.0, 3.5
  2. SOA – collection of services communicating only by exchanging messages. Messages trigger certain business logic. Services may return a response message to indicate what has been done.
  3. Contract of a service – format of messages, what is done when you receive a message, what responses can be expected, Awhat happens when something goes wrong – fault message
  4. WCF Contract – Service Contract (what operations/messages) – WSDL, Data Contract (Structure of payload of messages) – XSD, Message Contract (Headers in the messages) – SOAP, Operation Contract (?)
  5. Keywords: XML, XSD, SOAP, WSDL, WS-* (Addressing, Security, Policy, Reliable Messaging, Atomic Transaction, …)
  6. MEP – Message Exchange Pattern – Request-response, one-way, duplex
  7. System.ServiceModel
  8. ServiceContractAttribute: Name, Namespace, CallbackContract, ProtectionLevel, ConfigurationName, SessionMode
  9. OperationContractAttribute: Name, Action, ReplyAction, IsOneWay, ProtectionLevel, IsInitiating, IsTerminating
  10. REST: Representational Entity State Transfer – Web Service Interface for “Consumer Applications”. Follows CRUD (Create Read Update Delete) pattern
  11. SOAP: Simple Object Access Protocol – Web Service Interace for “Business Applications” for exchanging complex data. Messages contain an envelope and a body.
  12. WCF messages can be in either format SOAP or REST
  13. Hosting WCF Services: IIS, Managed Service on Windows, Standalone Windows Application, WAS.
  14. Endpoints – a resource on the network to which messages can be sent. A Service is a set of endpoints. Both client and service have an endpoint.
  15. Endpoint is defined by ABC: Address (where), Binding (how), Contract (what).
  16. Address – where the messages should be sent. A URI
  17. Binding – defines the channel used to communicate with an endpoint.
  18. Channel – composed of a series of binding elements (transport – HTTP, TCP, Named Pipers, PerChannel, MSMQ; security; transactions).
  19. basicHttpBinding – for communicating with Web Services with WS-I BP 1.1
  20. wsHttpBinding – common WS-* protocol for secure, reliable and transacted messaging
  21. ServiceHost class creates endpoints of a service
  22. Add Metadata Exchange (MEX) endpoint – for discoverability, to obtain ABCs of the service and WSDL. Called when you click on “Add Service Reference”, or when you use svcutil.exe

Events – subscribe to events, event handlers, publishing events

[Reference: Programming WCF, 3ed, Juval Lowy]

Recreate UML?

dot -T png -o uml.png this.dot
cat this.dot
digraph G {
    fontname = "Helvetica"
    fontsize = 8

    node [
        fontname = "Helvetica"
        fontsize = 10
        shape = "record"
    ]
    nodesep=0.25;
    ranksep=0.5;

    edge [
        fontname = "Helvetica"
        fontsize = 8
    ]

    edge [
        dir = "back"
        arrowtail = "empty"
    ]

    IMyEvents [label="{IMyEvents|+OnEvent1()\l+OnEvent2(n : int)\l+OnEvent3(n : int, t : string)\l}"]
    ISubscriptionService [label="{ISubscriptionService|+Subscribe(event : string)\l+Unsubscribe(event : string)\l}"]
    PublishService [label="{PublishService\<IMyEvents\>|-FireEvent(args : object[])\l-Publish(event : string, args : object[])\l}"]

    IMySubscriptionService [label="{IMySubscriptionService|+Callback = IMyEvents\l}"]
    SubscriptionManager [label="{SubscriptionManager\<IMyEvents\>|+Subscribe(event : string)\l+Unsubscribe(event : string)\l|-store : Dictionary\<string,List\<IMyEvents\>\>\l}"]

    IMyEvents -> MyPublishService
    PublishService -> MyPublishService

    SubscriptionManager -> MySubscriptionService
    IMySubscriptionService -> MySubscriptionService
    ISubscriptionService -> IMySubscriptionService
}


Publish/Subscribe

  1. Server Side
    Lets start with interface definitions (note these are only Service Contracts)

    // A general purpose interface to subscribe/unsubscribe
    [ServiceContract]
    public interface ISubscriptionService
    {
    	[OperationContract]
    	void Subscribe(string eventOperation);
    
    	[OperationContract]
    	void Unsubscribe(string eventOperation);
    }
    
    // These are the events that we will emit
    [ServiceContract]
    public interface IMyEvents
    {
    	[OperationContract(IsOneWay = true)]
    	void OnEvent1();
    
    	[OperationContract(IsOneWay = true)]
    	void OnEvent2(int number);
    
    	[OperationContract(IsOneWay = true)]
    	void OnEvent3(int number, string text);
    }
    
    // We let you subscribe to the above events
    [ServiceContract(CallbackContract = typeof(IMyEvents))]
    public interface IMySubscriptionService : ISubscriptionService
    {
    }
    		

    Let us put down some concrete stuff to let folks subscribe/unsubscribe

    public abstract class SubscriptionManager<T> where T : class
    {
    	static Dictionary<string, List<T>> m_TransientStore;
    
    	static SubscriptionManager()
    	{
    		m_TransientStore = new Dictionary<string, List<T>>();
    		string[] methods = GetOperations();
    		Action<string> insert = (methodName) =>
    		{
    			m_TransientStore.Add(methodName, new List<T>());
    		};
    		Array.ForEach(methods, insert);
    	}
    
    	static string[] GetOperations()
    	{
    		System.Reflection.MethodInfo[] methods = typeof(T).GetMethods(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.FlattenHierarchy | System.Reflection.BindingFlags.Instance);
    		List<string> operations = new List<string>(methods.Length);
    
    		Action<System.Reflection.MethodInfo> add = (method) =>
    		{
    			System.Diagnostics.Debug.Assert(!operations.Contains(method.Name));
    			operations.Add(method.Name);
    		};
    		Array.ForEach(methods, add);
    		return operations.ToArray();
    	}
    
    	//Transient subscriptions management 
    	internal static T[] GetTransientList(string eventOperation)
    	{
    		lock (typeof(SubscriptionManager<T>))
    		{
    			System.Diagnostics.Debug.Assert(m_TransientStore.ContainsKey(eventOperation));
    			if (m_TransientStore.ContainsKey(eventOperation))
    			{
    				List<T> list = m_TransientStore[eventOperation];
    				return list.ToArray();
    			}
    			return new T[] { };
    		}
    	}
    	static void AddTransient(T subscriber, string eventOperation)
    	{
    		lock (typeof(SubscriptionManager<T>))
    		{
    			List<T> list = m_TransientStore[eventOperation];
    			if (list.Contains(subscriber))
    			{
    				return;
    			}
    			list.Add(subscriber);
    		}
    	}
    	static void RemoveTransient(T subscriber, string eventOperation)
    	{
    		lock (typeof(SubscriptionManager<T>))
    		{
    			List<T> list = m_TransientStore[eventOperation];
    			list.Remove(subscriber);
    		}
    	}
    
    	public void Subscribe(string eventOperation)
    	{
    		lock (typeof(SubscriptionManager<T>))
    		{
    			T subscriber = OperationContext.Current.GetCallbackChannel<T>();
    			if (String.IsNullOrEmpty(eventOperation) == false)
    			{
    				AddTransient(subscriber, eventOperation);
    			}
    			else
    			{
    				string[] methods = GetOperations();
    				Action<string> addTransient = (methodName) =>
    				{
    					AddTransient(subscriber, methodName);
    				};
    				Array.ForEach(methods, addTransient);
    			}
    		}
    	}
    
    	public void Unsubscribe(string eventOperation)
    	{
    		lock (typeof(SubscriptionManager<T>))
    		{
    			T subscriber = OperationContext.Current.GetCallbackChannel<T>();
    			if (String.IsNullOrEmpty(eventOperation) == false)
    			{
    				RemoveTransient(subscriber, eventOperation);
    			}
    			else
    			{
    				string[] methods = GetOperations();
    				Action<string> removeTransient = (methodName) =>
    				{
    					RemoveTransient(subscriber, methodName);
    				};
    				Array.ForEach(methods, removeTransient);
    			}
    		}
    	}
    }		
    
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    public class MySubscriptionService : SubscriptionManager<IMyEvents>, IMySubscriptionService
    {
    }
    		

    With the above set up we have got all it needs for folks to start subscribing/unsubscribing.
    Next we need stuff to fire the events. There are 2 ways one can fire events:

    1. We expose an interface so that clients can tell us to fire events
    2. We unilaterally fire events when we feel like it
    public abstract class PublishService<T> where T : class
    {
    	protected static void FireEvent(params object[] args)
    	{
    		string action = OperationContext.Current.IncomingMessageHeaders.Action;
    		string[] slashes = action.Split('/');
    		string methodName = slashes[slashes.Length - 1];
    
    		FireEvent(methodName, args);
    	}
    
    	static void FireEvent(string methodName, params object[] args)
    	{
    		PublishTransient(methodName, args);
    	}
    
    	static void PublishTransient(string methodName, params object[] args)
    	{
    		T[] subscribers = SubscriptionManager<T>.GetTransientList(methodName);
    		Publish(subscribers, false, methodName, args);
    	}
    
    	static void Publish(T[] subscribers, bool closeSubscribers, string methodName, params object[] args)
    	{
    		System.Threading.WaitCallback fire = (subscriber) =>
    		{
    			Invoke(subscriber as T, methodName, args);
    			if (closeSubscribers)
    			{
    				using (subscriber as IDisposable)
    				{ }
    			}
    		};
    		Action<T> queueUp = (subscriber) =>
    		{
    			System.Threading.ThreadPool.QueueUserWorkItem(fire, subscriber);
    		};
    		Array.ForEach(subscribers, queueUp);
    	}
    	static void Invoke(T subscriber, string methodName, object[] args)
    	{
    		System.Diagnostics.Debug.Assert(subscriber != null);
    		Type type = typeof(T);
    		System.Reflection.MethodInfo methodInfo = type.GetMethod(methodName);
    		try
    		{
    			methodInfo.Invoke(subscriber, args);
    		}
    		catch (Exception e)
    		{
    			System.Diagnostics.Trace.WriteLine(e.Message);
    		}
    	}
    }
    
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    public class MyPublishService : PublishService<WcfServiceLibrary1.IMyEvents>, WcfServiceLibrary1.IMyEvents
    {
    	public void OnEvent1()
    	{
    		FireEvent();
    	}
    	public void OnEvent2(int number)
    	{
    		FireEvent(number);
    	}
    	public void OnEvent3(int number, string text)
    	{
    		FireEvent(number, text);
    	}
    }		
    		

    Anytime we want to fire an event we will call MyPublishService.OnEvent1().

    What next? Yes hook it up in a config file and we will be ready to roll.

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <system.web>
        <compilation debug="true" />
      </system.web>
      <system.serviceModel>
        <bindings>
          <netTcpBinding>
            <binding name = "ReliableTCP">
              <reliableSession enabled = "true"/>
            </binding>
          </netTcpBinding>
        </bindings>
        <client />
        <services>
          <service name = "WcfServiceLibrary1.MyPublishService">
            <host>
              <baseAddresses>
                <add baseAddress="net.tcp://localhost:8101/"/>
              </baseAddresses>
            </host>
            <endpoint
               address  = "MyEventService"
               binding  = "netTcpBinding"
               bindingConfiguration = "ReliableTCP"
               contract = "WcfServiceLibrary1.IMyEvents"
                />
            <endpoint address="mex"
                      binding="mexTcpBinding"
                      contract="IMetadataExchange"/>
          </service>
    
          <service name = "WcfServiceLibrary1.MySubscriptionService">
            <host>
              <baseAddresses>
                <add baseAddress="net.tcp://localhost:9101/"/>
              </baseAddresses>
            </host>
            <endpoint
               address  = "MySubscriptionManager"
               binding  = "netTcpBinding"
               bindingConfiguration = "ReliableTCP"
               contract = "WcfServiceLibrary1.IMySubscriptionService"
                />
            <endpoint address="MEX"
                      binding="mexTcpBinding"
                      contract="IMetadataExchange"/>
          </service>
        </services>
        <behaviors>
          <serviceBehaviors>
            <behavior>
              <serviceMetadata/>
              <serviceDebug includeExceptionDetailInFaults="True" />
            </behavior>
          </serviceBehaviors>
        </behaviors>
      </system.serviceModel>
    </configuration>		
    		

    Well lets roll then, put it in a simple console host.

    using System;
    using System.ServiceModel;
    
    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                ServiceHost host1 = new ServiceHost(typeof(WcfServiceLibrary1.MyPublishService));
                ServiceHost host2 = new ServiceHost(typeof(WcfServiceLibrary1.MySubscriptionService));
    
    			try
    			{
    				host2.Open();
    				host1.Open();
    
    				string s = host2.Description.Name;
    				Console.WriteLine("Running the Test Service: " + s);
    				Console.ReadLine();
    
    				host1.Close();
    				host2.Close();
    			}
    			catch (TimeoutException timeProblem)
    			{
    				Console.WriteLine(timeProblem.Message);
    			}
    			catch (CommunicationException commProblem)
    			{
    				Console.WriteLine(commProblem.Message);
    			}
            }
        }
    }		
    		
  2. Client Side
    Make your life easy and let VS2010 add a service reference to your SubscriptionService by giving it the following URL:
    “net.tcp://localhost:9101/MEX”

    using System.ServiceModel;
    using System;
    namespace WCFClientConsole
    {
        class Program
        {
            static void Main(string[] args)
            {
                EventHandler eventHandler = new EventHandler();
                InstanceContext context = new InstanceContext(eventHandler);
                ServiceReference1.MySubscriptionServiceClient client = new ServiceReference1.MySubscriptionServiceClient(context);
                client.Subscribe("OnEvent1");
    
                Console.WriteLine("Running the Test Client: ");
                Console.ReadLine();
            }
        }
    
        public class EventHandler : ServiceReference3.IMySubscriptionServiceCallback
        {
            public EventHandler()
            {
            }
    
            #region IMySubscriptionServiceCallback Members
            public void OnEvent1()
            {
                throw new System.NotImplementedException();
            }
    
            public void OnEvent2(int number)
            {
                throw new System.NotImplementedException();
            }
    
            public void OnEvent3(int number, string text)
            {
                throw new System.NotImplementedException();
            }
            #endregion
        }
    }		
    		

    Nothing can happen without configuration. Well this is automatically generated for you by svcutil.exe

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
        <system.serviceModel>
            <bindings>
                <netTcpBinding>
                    <binding name="NetTcpBinding_IMySubscriptionService" closeTimeout="00:01:00"
                        openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
                        transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions"
                        hostNameComparisonMode="StrongWildcard" listenBacklog="10"
                        maxBufferPoolSize="524288" maxBufferSize="65536" maxConnections="10"
                        maxReceivedMessageSize="65536">
                        <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                            maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                        <reliableSession ordered="true" inactivityTimeout="00:10:00"
                            enabled="true" />
                        <security mode="Transport">
                            <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" />
                            <message clientCredentialType="Windows" />
                        </security>
                    </binding>
                </netTcpBinding>
            </bindings>
            <client>
                <endpoint address="net.tcp://localhost:9101/MySubscriptionManager"
                    binding="netTcpBinding" bindingConfiguration="NetTcpBinding_IMySubscriptionService"
                    contract="ServiceReference3.IMySubscriptionService" name="NetTcpBinding_IMySubscriptionService">
                    <identity>
                        <userPrincipalName value="xxxx@yyyyyy.com" />
                    </identity>
                </endpoint>
            </client>
        </system.serviceModel>
    </configuration>		
    		
  3. Test: Run WCFTestClient.exe and have it connect to PublishService and fire off an OnEvent1() and you will be a happy winner of an “NotImplemented” exception caused by your first event.

Written by curious

September 15, 2010 at 9:00 am

Posted in dotNET

.NET: Setting up Configuration Service

Some useful paths:

  1. C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\svcutil.exe
  2. C:\Program Files\Microsoft Visual Studio 9.0\Common7\Tools\vsvars32.bat

Do this once

  1. Run “Start -> Visual Studio 2008 -> Visual Studio Command Prompt”
  2. Create a strong name for svcutil
    sn -Vr “C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\svcutil.exe”
    

Configuration Service Hosting Options
Windows host
IIS hosted client

Host Name Identifier FooBar Service Host
Cluster Name FooBar Service Cluster
Configuration Service Name Space FooBar.HostConfigurationImplementation
Settings Class Name Space FooBar.Settings
Host Environment Windows Application
Service Host Class Name Space FooBar.Host
Even Log Source FooBar Service Event Log
Node Svc Virtual Path foobar/node
Node Svc HTTP Port 8001
Config Svc Virtual Path foobar/config
Config Svc HTTP Port 8001
Database Server sqldbserver
SQL Login Mode SQL Authentication
Admin Login ID sa
Password ****
Name for New Configuration Database FooBarServiceRepositoryDB

Note: The SQL Server database instance will be created with login: “config” and password “yyy”. The connection string for the Repository DB will be put in “generatedcode/app.config” file. Whenever you change DB password, you should update the app.config file.

Create a Configuration Reposity in the Database

  1. Run “Repository Creation Tool”
    Start -> .NET Stock Trader 2.0 -> Configuration Service -> Repository Creation Tool (C:\stocktrader\Builds\RepositoryCreate\ConfigService.RepositoryCreate.exe)
  2. Enter Information from the table below
  3. Create the database
  4. It will generate a lot of C# Code files in “C:\stocktrader\Builds\RepositoryCreate\generatedcode\”. (App.config, program.cs, WinHostConsole.cs, Settings.cs, ConfigurationAction.cs, ConfigurationService.cs)

Create Windows Application that will host your WCF Service

  1. Create Windows Application project called “FooBarHost” (remember name space you wanted was: “FooBar.Host”)
  2. Remove “Form1.cs”, “Program.cs” files that Visual Studio created for you.
  3. In Project Properties, on “Application” tab change “Assembly Name” to “FooBar.Host”, and also change “Default namespace” to “FooBar.Host”
  4. Give a strong name to your assembly. Go to “Signing” tab and check “Sign the assembly”. Choose “New” to “Create a Strong Name Key file”. Enter a “Key file name” = “foobarhost.snk”.  Leave “Protect my key file with a password” unchecked.
  5. Add “Program.cs”, “WinHostConsole.cs” and “app.config” generated files to the project. Use “Add Existing Item”.
  6. Add references to
    1. “C:\Windows\Microsoft.NET\Framework\v3.0\Windows Communication Foundation” DLLs: System.ServiceModel.dll, System.Runtime.Serialization.dll
    2. On 64bit look in, “C:\Windows\Microsoft.NET\Framework64\v3.0\Windows Communication Foundation”
    3. Add reference to “C:\stocktrader\SharedLibraries\Configuration\” assemblies:
      • ConfigService.CacheDataContract
      • ConfigService.DALSQLHelper
      • ConfigService.IConfigActions
      • ConfigService.RuntimeHostData
      • ConfigService.ServiceConfigurationBase
      • ConfigService.ServiceConfigurationContract
      • ConfigService.ServiceHostConsoleBase
      • ConfigService.ServiceNodeCommunicationContract
      • ConfigService.ServiceNodeCommunicationImplementation
      • ConfigService.ServiceConfiguration.{DALFactory,DALSQLServer,IDAL}

Create a project for “HostConfigurationImplementation” inside the same Solution

  1. Create a C# Class Library project in the “FooBarHost” solution, name it “FooBarHostConfigurationImplementation”
  2. Remove “Class1.cs” file and add “ConfigurationAction.cs”, “ConfigurationService.cs”
  3. Also change the Assembly Name, and Default Namespace to “FooBar.HostConfigurationImplementation” in project properties.
  4. Create a strong name for the assembly by Signing it with a key file.
  5. Add references to:
    1. System.ServiceModel.dll, System.Runtime.Serialization.dll
    2. Add reference to “C:\stocktrader\SharedLibraries\Configuration\” assemblies:
      • ConfigService.IConfigActions
      • ConfigService.RuntimeHostData
      • ConfigService.ServiceConfigurationBase
      • ConfigService.ServiceConfigurationContract
      • ConfigService.ServiceConfigurationHelper
      • ConfigService.ServiceConfigurationUtility
      • ConfigService.ServiceNodeCommunication.DataContract
      • ConfigService.ServiceConfiguration.{DALFactory,DALContract,IDAL}

Create Settings project

  1. Create a C# Class Library project in the “FooBarHost” solution, name it “FooBarSettings”
  2. Remove “Class1.cs” and add “Settings.cs” from generated code
  3. Change Assembly Name and Default Namespace to “FooBar.Settings”
  4. Create a strong name
  5. Add a reference to assembly: ConfigService.ServiceConfigurationBase

Go back to the Host and HostConfigurationImplementation projects and

  1. Add a reference to projects: FooBar.HostConfigurationImplementation and FooBar.Settings to “FooBarHost” project.
  2. Add a reference to projects: FooBar.Settings to “FooBarHostConfigurationImplementation” project.

Running the application service

  1. You can run the FooBarHost application and connect to ConfigWeb: http://localhost/configweb
  2. Select http://localhost:8181/foobar/config as the endpoint address in ConfigWeb login page. User: localadmin, Password: yyy
  3. User management: In Config Web/Windows Host go to “Config Users” tab

Written by curious

September 11, 2010 at 8:00 am

Posted in dotNET