Friday, May 22, 2009

Putting C# attributes to use


Recently in an interview I was asked if I had worked with attributes, I had, and I told them how, I don’t know why I didn’t put it on my blog, anyways now I will do it.

What I have done is that, I have created 2 attribues [notNULL] and [notNIL] these can be applied to any function parameter, what happens is, if you pass null to a function that has the parameter decorated as [notNULL] then a ArgumentNullException is thrown and for [notNIL] ArgumentException is thrown.

To achieve this, the class which is going to use these attributes must be decorated with another attribute ([the] in our case) this attribute adds a property for itself and this property adds a sink where you get a hook and can query the method/parameter/etc and execute any business logic you want – in my case I am simply checking if the parameter has the said attributes and throw exception.

The Client Program (Program.cs)
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

using System.Runtime.Remoting.Activation;

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
theClass theObject = new theClass();
theObject.operate("a",3,null);

theChild theChildObject = new theChild();
theChildObject.working("");
}
}
}

The Class (theClass.cs)

using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApplication1
{
[the]
class theClass:ContextBoundObject
{
public void operate([notNULL]string s, int a, [notNIL]string ss)
{
Console.WriteLine("theClass did its work");
}
}
[the]
class theChild : theClass
{
public void working([notNULL] string s)
{
Console.WriteLine("theChild did its work");
}
}
}

NotNULL/NotNIL Attributes (notNULL.cs)

using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApplication1
{
[AttributeUsage(AttributeTargets.Parameter)]
class notNULLAttribute:Attribute
{
public notNULLAttribute() { }

}
[AttributeUsage(AttributeTargets.Parameter)]
class notNILAttribute : Attribute
{
public notNILAttribute() { }

}
}

The Attribute (theAttribute.cs)

using System;
using System.Collections.Generic;
using System.Runtime.Remoting.Contexts;
using System.Runtime.Remoting.Activation;
using System.Text;

namespace ConsoleApplication1
{
[AttributeUsage(AttributeTargets.Class,Inherited=true)]
class theAttribute:Attribute,IContextAttribute
{
public theAttribute()
{ }

public void GetPropertiesForNewContext(IConstructionCallMessage msg)
{
theProperty property = new theProperty();
msg.ContextProperties.Add(property);
}

public bool IsContextOK(Context ctx, IConstructionCallMessage msg)
{
return false;
}
}
}

The Property (theProperty.cs)

using System;
using System.Collections.Generic;
using System.Runtime.Remoting.Contexts;
using System.Runtime.Remoting.Messaging;
using System.Text;

namespace ConsoleApplication1
{
class theProperty:IContextProperty,IContributeServerContextSink
{
public theProperty() { }

public string Name { get { return "MyProperty"; } }

public bool IsNewContextOK(Context newctx) { return true; }

public void Freeze(Context newContext){}

public IMessageSink GetServerContextSink(IMessageSink nextSink)
{
return new theSink(nextSink);
}
}
}

The Sink (theSink.cs)

using System;
using System.Collections.Generic;
using System.Runtime.Remoting.Contexts;
using System.Runtime.Remoting.Activation;
using System.Runtime.Remoting.Messaging;
using System.Reflection;
using System.Text;

namespace ConsoleApplication1
{
class theSink:IMessageSink
{
private IMessageSink next;

public theSink(IMessageSink next) { this.next = next; }

public IMessage SyncProcessMessage(IMessage msg)
{
if (msg is IMethodMessage)
{
IMethodMessage methodMessage = msg as IMethodMessage;

MethodBase methodInfo = methodMessage.MethodBase;

ParameterInfo[] parameters = methodInfo.GetParameters();
foreach (ParameterInfo p in parameters)
{
object[] attributes = p.GetCustomAttributes(true);
foreach (Attribute a in attributes)
{
if (a.GetType() == typeof(notNULLAttribute))
{
//Console.WriteLine("found " + p.ToString() + " at position "+p.Position+" which has notnull attribute");
if (null == methodMessage.GetArg(p.Position))
{
Console.WriteLine("Error : " + p.ToString() + " cannot be null in "+methodInfo.Name);
throw new ArgumentNullException("Not null attribute violated");
}
}
if (a.GetType() == typeof(notNILAttribute))
{
//Console.WriteLine("found " + p.ToString() + " at position "+p.Position+" which has notnull attribute");
if(null == methodMessage.GetArg(p.Position) ||
"" == methodMessage.GetArg(p.Position).ToString())
{
Console.WriteLine("Error : " + p.ToString() + " cannot be nil in "+methodInfo.Name);
throw new ArgumentException("Not nil attribute violated");
}
}
}
}
}
IMessage replyMessage = next.SyncProcessMessage(msg);
return replyMessage;
}

public IMessageSink NextSink { get { return this.next; } }

public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink)
{
return null;
}
}
}

Wednesday, May 20, 2009

IIS, WCF apps, ports, etc


I have very little experience on Web development/IIS, and it was difficult for me to understand how self hosting was working in WCF, heres what I thought :

I start my application that is hosting the service, now when i request its metadatabehaviour through my web browser, I get the wsdl, however at this time my IIS is not running and the URL is something like http://localhost:8001/service. According to me the moment I say localhost the request should go to my IIS server and from here a response should be generated, but how was this working even when IIS was stopped, that means my application was serving the wsdl response, now how can 2 applications respond to HTTP, only one can have complete control. However I soon found out that my assumptions were wrong.

Heres what really happens, when you start a website on IIS, it is typically on port 80, and when my application hosted the service I had hosted it on 8001, and hence they work independently of each other, try starting the app on port 80 and then start IIS – it throws error, so it means there can be multiple apps that can handle HTTP, just that each handles a unique set of port numbers.

Sunday, May 03, 2009

Factory Method/Virtual Constructor


Define an interface for creating an object, but let subclass decide which class to instantiate.

Motivation: Frameworks use abstract classes to define and maintain relationships between objects. Frameworks are often responsible for creating objects.

image

Here, Application and Document are abstract classes. Now application is responsible is responsible for creating a document, but which document???

While working you will have a instance of concrete application pointed by abstract Application, now you call a Factory Method (NewDocument in our case) on the Application which in turn calls CreateDocument on concrete application – this now knows what to return –> based on itself.

Consequence:

  • You get a hook at subclass
  • You can connect parallel class hierarchy

You can use templates if you want to avoid subclass
You can take in a parameter in Factory Method and decide which class to instantiate
You might want to create object pool
You can name constructor private or protected

Factory method requests for object creating, new forces

Called within Template Method
This is creation through inheritance
Prototype is creation through delegation

Posting code

If you see my previous post you will see that my code is nicely decorated with colors and helpful utilities - copy to clipboard, etc. and it does not have any line spacing issues - things that I have been struggling for a long time now...

Last weekend I finally did a lot of RnD and came across http://alexgorbatchev.com/wiki/SyntaxHighlighter This guy has a bunch of styles and scripts which you have to include in you blogger template and done. Next time you need to post some code just wrap you code in <pre class="brush:c#"> and you are done.

This is awesome, but 1 issue with this is that, it does not recognize custom classes, and you cannot modify the scripts to include all the custom classes you would ever need – for this I liked “Paste from VisualStudio” plug-in for Windows Live Writer. It will give me the exact colors Visual Studio uses.

Only if we could combine the 2 :)

First WCF server/client app

After a lot of trial and errors I was finally able to get the server and client running, here’s my code

I have a dll referenced in server which has the Service1 and IService1

Server:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using WcfServiceLibrary1;
using System.ServiceModel.Description;

namespace WCFServer
{
class Program
{
static void Main(string[] args)
{
ServiceHost h = new ServiceHost(typeof(Service1));
h.AddServiceEndpoint(typeof(IService1), new NetTcpBinding(), "net.tcp://localhost:8080/service");

ServiceMetadataBehavior metadataBehavior;
metadataBehavior = h.Description.Behaviors.Find();
if (metadataBehavior == null)
{
metadataBehavior = new ServiceMetadataBehavior();
metadataBehavior.HttpGetUrl = new Uri("http://localhost:8001/service");
metadataBehavior.HttpGetEnabled = true;
metadataBehavior.ToString();
h.Description.Behaviors.Add(metadataBehavior);
}

h.Open();
Console.Read();
h.Close();
}
}
}


In the server, the metadata behavior is important, coz thats the only way to discover all the available bindings, so if you dont have metadata, your client will never be able to discover your service.

Once your server is up and running, you need to add the service reference, to do that - enter the service URL as http://localhost:8001/service and hit Ok, visual studio will generate the proxy classes, config file and give you Service1Client class using which you can invoke operations such as GetData.

Client:



static void Main(string[] args)
{
Service1Client c = new Service1Client();
string s = c.GetData(5);
}


Technorati Tags: