Develop and Consume OData Web Services in WCF

What is OData?

OData is an Open Data Protocol used to access data from various sources like Relational databases, file systems, etc. and exposes it to the consumers that can query or update data. OData is based upon Web technologies such as HTTP, Atom Publishing Protocol (AtomPub) and JSON to provide access to information from variety of data sources. Consumers can query the data using HTTP protocol and get the results in AtomPub and JSON formats. These are the formats through which the service can deliver the requested resources or collection of entities.

OData is released under the Open Specification Promise http://www.microsoft.com/openspecifications/en/us/programs/osp/default.aspx and anyone can freely interoperate with OData implementations.

Developing WCF Service using OData Protocol

Microsoft has first introduced OData support in Visual Studio 2008 SP1 in terms of ADO.Net Data Services (subsequently known as WCF Data Services). Developers can create services on the fly and exposes data using Entity Framework or LINQ 2 SQL ORM tools.

Let’s create a simple WCF Data Service and expose data using Entity Framework.

  1. Start Visual Studio 2010 and create a new WCF Service Application project.


  1. Right click the WCF Service Application project and click on the “Add New Item”, then select WCF Data Service.


  2. If you open the WCF Data Service class file you can see the Class will be derived from the generic DataService class. This is the main entry point for developing WCF Data services. We have to specify the data source class name. In order to proceed further I will add entity framework model which creates the entities model on the fly.
  3. Right click on the Service Project and Add “ADO.Net Entity Data Model” from the dialog.


    When you add ADO.Net Entity Model it will ask you to select the data source, go through the wizard by selecting the data source and finish a dialog.

  4. Now open the .edmx file click on properties.


    Here’s the entity container named as “DDMSEntities”. Just specify the name DDMSEntities in your WCF Data Service base class like below

public class WcfDataService1 : DataService<DDMSEntities>

  1. You can now add the SetEntitySetAccessRule for each entity you want to expose. Default configuration is to deny access to resources. When a service is initialized the access rights must be enabled.

    Sample code snippet below


public static void InitializeService(DataServiceConfiguration config)
{

// TODO: set rules to indicate which entity sets and service operations are visible, updatable, etc.

config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;

config.SetEntitySetAccessRule (“Levels”, EntitySetRights.AllRead);

config.SetEntitySetAccessRule (“NodeTypes”, EntitySetRights.All);

}

In Above code, I have added two tables i.e. Levels and NodeTypes and given permissions as AllRead. There are many permission levels you can set as follows. Below are the enums of EntitySetRights with their description

  • All – Authorize to create, read, update and delete data.
  • AllRead- Authorize to read data.
  • AllWrite- Authorize to write data.
  • None- Denies all rights to access data.
  • ReadMultiple – Authorize to read sets of data.
  • ReadSingle – Authorize to read single data of items.
  • WriteAppend- Authorize to create new data items in the data sets.
  • WriteDelete –Authorize to delete data items from the data sets.
  • WriteMerge – Authorize to merge data.
  • WriteReplace – Authorize to replace data.
  1. Now let’s build a service and test it. Once you hit the web service in a browser, you will see the page as below


    The above feed representing the data as per Atom Syndication format. There are two entity collections namely “Levels” and “NodeTypes”.

                                      http://localhost:32555/WcfDataService1.svc/Levels?filter= LevelTree gt

                                     “gt” is used for greater than where as “lt” is used for less than.

Consuming WCF Data Service in Web Application

  1. Create a new Web Application project in Visual Studio
  2. Add a service reference by right clicking on Add Service Reference and select the newly service created.


  3. Add a button to call the service on its click event.
  4. On the click event you can consume the service like below

Services.DMSEntities.DDMSEntities entities = new Services.DMSEntities.DDMSEntities(new
Uri(http://localhost:32555/WcfDataService1.svc&#8221;));

var lst = entities.Levels.FirstOrDefault();

This will return the first item in the collection. You can execute all CRUD operations depending on the rule set in the Service for that entity.

Hope this helps, happy coding!

Problem loading ASP.Net project after installing VS 2010 SP1

Sometimes developer faces this problem on loading existing web projects that were hosted on local IIS server and using the same port number that has been used by the IIS Express for particular websites. IIS Express installed by default when you apply the SP1 for Visual Studio 2010.

In my case, I installed VS 2010 SP1 to install Silverlight 5 Tools for VS 2010 and when opened my existing web project which was earlier hosted on my Local IIS server using the same port no i.e. 8080, came across this error.

In order to rectify, the simplest way is to change the port no in the applicationhost.config file placed under [Win_Drive]:\Users\[User]\Documents\IISExpress\config folder. When open the applicationhost.config file you will find the <bindings> tag under <site> tag followed with the port no.

Change the port no and don’t forget to save the file. Now try reloading the project and it opens without any issue.

Implementing Repository Pattern with Entity Framework – Code First Model Approach

When working with Entity Framework – Code First model approach, developer creates POCO entities for Database tables. The benefit of using Code First model is to have POCO entity for each table that can be used as either WCF Data Contracts or you can apply your own custom attributes to handle Security, Logging, etc. and there is no mapping needed as we used to do in Entity Framework (Model First) approach if the application architecture is n-tier based.

Considering the Data Access layer, we will implement a repository pattern that encapsulates the persistence logic in a separate class. This class will be responsible to perform database operations. Let’s suppose the application is based on n-tier architecture and having 3 tiers namely Presentation, Business and Data Access. Common library contains all our POCO entities that will be used by all the layers.

Presentation Layer: Contains Views, Forms

Business Layer: Managers that handle logic functionality

Data Access Layer: Contains Repository class that handles CRUD operations

Common Library: Contain POCO entities.

We will implement an interface named “IRepository” that defines the signature of all the appropriate generic methods needed to perform CRUD operation and then implement the Repository class that defines the actual implementation of each method. We can also instantiate Repository object using Dependency Injection or apply Factory pattern.

Code Snippet: IRepository


public
interface
IRepository : IDisposable

{


///
<summary>


/// Gets all objects from database


///
</summary>


///
<returns></returns>


IQueryable<T> All<T>() where T : class;


///
<summary>


/// Gets objects from database by filter.


///
</summary>


///
<param name=”predicate”>Specified a filter</param>


///
<returns></returns>


IQueryable<T> Filter<T>(Expression<Func<T, bool>> predicate) where T : class;


///
<summary>


/// Gets objects from database with filting and paging.


///
</summary>


///
<typeparam name=”Key”>


///
<param name=”filter”>Specified a filter</param>


///
<param name=”total”>Returns the total records count of the filter.</param>


///
<param name=”index”>Specified the page index.</param>


///
<param name=”size”>Specified the page size</param>


///
<returns></returns>


IQueryable<T> Filter<T>(Expression<Func<T, bool>> filter, out
int total, int index = 0, int size = 50) where T : class;


///
<summary>


/// Gets the object(s) is exists in database by specified filter.


///
</summary>


///
<param name=”predicate”>Specified the filter expression</param>


///
<returns></returns>


bool Contains<T>(Expression<Func<T, bool>> predicate) where T : class;


///
<summary>


/// Find object by keys.


///
</summary>


///
<param name=”keys”>Specified the search keys.</param>


///
<returns></returns>

T Find<T>(params
object[] keys) where T : class;


///
<summary>


/// Find object by specified expression.


///
</summary>


///
<param name=”predicate”></param>


///
<returns></returns>

T Find<T>(Expression<Func<T, bool>> predicate) where T : class;


///
<summary>


/// Create a new object to database.


///
</summary>


///
<param name=”t”>Specified a new object to create.</param>


///
<returns></returns>

T Create<T>(T t) where T : class;


///
<summary>


/// Delete the object from database.


///
</summary>


///
<param name=”t”>Specified a existing object to delete.</param>


int Delete<T>(T t) where T : class;


///
<summary>


/// Delete objects from database by specified filter expression.


///
</summary>


///
<param name=”predicate”></param>


///
<returns></returns>


int Delete<T>(Expression<Func<T, bool>> predicate) where T : class;


///
<summary>


/// Update object changes and save to database.


///
</summary>


///
<param name=”t”>Specified the object to save.</param>


///
<returns></returns>


int Update<T>(T t) where T : class;


///
<summary>


/// Select Single Item by specified expression.


///
</summary>


///
<typeparam name=”T”></typeparam>


///
<param name=”expression”></param>


///
<returns></returns>

T Single<T>(Expression<Func<T, bool>> expression) where T : class;


void SaveChanges();


void ExecuteProcedure(String procedureCommand, params
SqlParameter[] sqlParams);

}

Code Snippet: Repository

public
class
Repository : IRepository

{


DbContext Context;


public Repository()

{

Context = new
DBContext();

}


public Repository(DBContext context)

{

Context = context;

}


public
void CommitChanges()

{

 Context.SaveChanges();

}


public T Single<T>(Expression<Func<T, bool>> expression) where T : class

{


return All().FirstOrDefault(expression);

}


public
IQueryable<T> All<T>() where T : class

{


return Context.Set().AsQueryable();

}


public
virtual
IQueryable<T> Filter<T>(Expression<Func<T, bool>> predicate) where T : class

{


return Context.Set<T>().Where<T>(predicate).AsQueryable<T>();

}


public
virtual
IQueryable<T> Filter<T>(Expression<Func<T, bool>> filter, out
int total, int index = 0, int size = 50) where T : class

{


int skipCount = index * size;


var _resetSet = filter != null ? Context.Set().Where(filter).AsQueryable() : Context.Set().AsQueryable();

 _resetSet = skipCount == 0 ? _resetSet.Take(size) : _resetSet.Skip(skipCount).Take(size);

total = _resetSet.Count();


return _resetSet.AsQueryable();

}


public
virtual T Create(T TObject) where T : class

{


var newEntry = Context.Set().Add(TObject);

Context.SaveChanges();


return newEntry;

}


public
virtual
int Delete(T TObject) where T : class

{

 Context.Set().Remove(TObject);


return Context.SaveChanges();

}


public
virtual
int Update(T TObject) where T : class

{


try

{


var entry = Context.Entry(TObject);

 Context.Set().Attach(TObject);

entry.State = EntityState.Modified;


return Context.SaveChanges();

}


catch (OptimisticConcurrencyException ex)

{


throw ex;

}

}


public
virtual
int Delete<T>(Expression<Func<T, bool>> predicate) where T : class

{


var objects = Filter<T>(predicate);


foreach (var obj in objects)

Context.Set<T>().Remove(obj);


return Context.SaveChanges();

}


public
bool Contains<T>(Expression<Func<T, bool>> predicate) where T : class

{


return Context.Set<T>().Count<T>(predicate) > 0;

}


public
virtual T Find<T>(params
object[] keys) where T : class

{


return (T)Context.Set<T>().Find(keys);

}


public
virtual T Find<T>(Expression<Func<T, bool>> predicate) where T : class

{


return Context.Set<T>().FirstOrDefault<T>(predicate);

}


public
virtual
void ExecuteProcedure(String procedureCommand, params
SqlParameter[] sqlParams){

 Context.Database.ExecuteSqlCommand(procedureCommand, sqlParams);

}


public
virtual
void SaveChanges()

{

Context.SaveChanges();

}


public
void Dispose()

{


if (Context != null)

Context.Dispose();

}

}

The benefit of using Repository pattern is that all the database operations will be managed centrally and in future if you want to change the underlying database connector you can add another Repository class and defines its own implementation or change the existing one.

Logging Messages from Windows Service to Windows Form using WCF Duplex Messaging

As you all know windows services run in background and user can start or configure them through Services panel in Windows Operating System. In order to do the logging to check what the service is doing you can log messages in database, message queues, event logs etc. But in order to send back and forth messages to any windows application to show real time task execution is only possible via TCP socket connection, remoting etc.

In this post I will show you the way of logging messages from Windows Services to Windows form based Monitor application using WCF Duplex Messaging.

Step 1: Creating WCF Service Library

  1. Create a WCF Service Library project from Visual Studio
  2. Add a Service Contract interface named as “IMonitorService”

[ServiceContract(

Name = “IMonitorService”,

SessionMode = SessionMode.Required,

CallbackContract = typeof(IMonitorServiceCallback))]


public
interface
IMonitorService

{

[OperationContract]


void Login();

[OperationContract]


void Logout();

[OperationContract]


void LogMessages(String message);

}

    In the above code, I have created an interface and provided three methods signature Login, Logout and LogMessages. Login and Logout will be used to connect or disconnect to the Service and LogMessages is used to log messages to client. You will notice that in the ServiceContract attribute I have specified CallbackContract which actually holds the type information of the Call back contract interface through which when the client invoke any of the login, logout or logmessages server can get the callbackcontract object and sends the response back to client itself.

  1. Here is the code for IMonitorServiceCallback contract interface.


public
interface
IMonitorServiceCallback

{

[OperationContract]


void NotifyClient(String message);

}

    In the above code there is a callback contract interface which holds one method signature “NotifyClient” which takes string as a parameter. Server can call NotifyClient method and send messages to the connected clients.

  1. Now create another class MonitorService and implement IMonitorService interface. Following code shows the complete

    code shows the complete implementation.

[ServiceBehavior(

ConcurrencyMode = ConcurrencyMode.Reentrant,

InstanceContextMode = InstanceContextMode.PerCall)]


public
class
MonitorService : IMonitorService

{


public
static
List<IMonitorServiceCallback> callBackList = new
List<IMonitorServiceCallback>();


public MonitorService()

{

}


public
void Login()

{


IMonitorServiceCallback callback = OperationContext.Current.GetCallbackChannel<IMonitorServiceCallback>();


if (!callBackList.Contains(callback))

{

callBackList.Add(callback);

}

}


public
void Logout()

{


IMonitorServiceCallback callback = OperationContext.Current.GetCallbackChannel<IMonitorServiceCallback>();


if (callBackList.Contains(callback))

{

callBackList.Remove(callback);

}

callback.NotifyClient(“You are Logged out”);

}


public
void LogMessages(string message)

{


foreach (IMonitorServiceCallback callback in callBackList)

{

callback.NotifyClient(message);

}

}

The above code shows the implementation of the IMonitorService interface.

Step 2: Create Windows Service project and use WCF Service Library

  1. Create a new “Windows Service” project using Visual Studio.
  2. In the Start method write some code to let service app do some work.
  3. Add project reference of the WCF Service Application
  4. Initialize the ServiceHost object of WCF framework

    ServiceHost host = new
    ServiceHost(typeof(MonitorService));

host.Open();

  1. Implement the LogMessage method and notify callback contracts.


foreach (IMonitorServiceCallback callback in
MonitorService.callBackList)

{

callback.NotifyClient(message);

}

  1. App.config for Windows Service

<?xml
version=1.0
encoding=utf-8 ?>

<configuration>

<system.web>

<compilation
debug=true />

</system.web>

<system.serviceModel>

<bindings>

<netTcpBinding>

<binding
name=DefaultNetTCPBinding
receiveTimeout=Infinite>

<reliableSession
inactivityTimeout=Infinite />

</binding>

</netTcpBinding>

</bindings>

<services>

<service
name=MonitorService>

<host>

<baseAddresses>

<add
baseAddress=net.tcp://localhost:9909/MonitorService/ />

</baseAddresses>

</host>

<!– Service Endpoints –>

<!– Unless fully qualified, address is relative to base address supplied above –>

<endpoint


address=service


binding=netTcpBinding
bindingConfiguration=DefaultNetTCPBinding


contract=IMonitorService


name=TcpBinding />

</service>

</services>

<behaviors>

<serviceBehaviors>

<behavior>

<!– To avoid disclosing metadata information,

set the value below to false and remove the metadata endpoint above before deployment –>

<serviceMetadata
httpGetEnabled=False/>

<!– 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>

</system.serviceModel>

</configuration>

Step 3: Developing Monitor Application

  1. Create a new Windows Application project using Visual Studio.
  2. Add RichTextBox control to log messages
  3. Add two buttons connect and disconnect.
  4. Now Add the WCF Service reference
  5. Implement Login, Logout and NotifyClient messages
  6. Add following code in the Login method
  7. Implement IMonitorServiceCallback interface and write below code.


try

{

client = new
MonitorServiceClient(new
InstanceContext(this), “TcpBinding”);

client.Open();

client.Login();

WriteTextMessage(“Monitor successfully connected to the Windows Service for logging messages”);

}


catch (Exception ex)

{

WriteTextMessage(“Couldn’t connect to the Service, cause “ + ex.Message);

}

  1. Add following code in the Logout nethod

client.Close();

  1. Add following code in the NotifyClient method.

public
void LogMessage(string message)

{


if (this.InvokeRequired == false)

{


this.BeginInvoke(new
WriteMessage(WriteTextMessage),message);

}


else

{


this.Invoke(new
WriteMessage(WriteTextMessage), message);

}

}

  1. As the application thread is different so we need to invoke the WriteTextMessage using BeginInvoke. In that case I have declared a delegate with the same method signature as of WriteTextMessage and set messages in the RichTextBox control.

public
delegate
void
WriteMessage(String str);


public
void WriteTextMessage(String str)

{

rchTextBox.Text += str + “\n”;

rchTextBox.ScrollToCaret();

}

  1. App.config for Monitor App

<?xml
version=1.0
encoding=utf-8 ?>

<configuration>

<appSettings>

<add
key=DatabaseServer
value=.\sqlexpress/>

</appSettings>

<system.serviceModel>

<bindings>

<netTcpBinding>

<binding
name=TcpBinding
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=false />

<security
mode=Transport>

<transport
clientCredentialType=Windows
protectionLevel=EncryptAndSign />

<message
clientCredentialType=Windows />

</security>

</binding>

</netTcpBinding>

<wsDualHttpBinding>

<binding
name=WSDualHttpBinding_IMonitorService
closeTimeout=00:01:00


openTimeout=00:01:00
receiveTimeout=00:10:00
sendTimeout=00:01:00


bypassProxyOnLocal=false
transactionFlow=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 />

<reliableSession
ordered=true
inactivityTimeout=00:10:00 />

<security
mode=Message>

<message
clientCredentialType=Windows
negotiateServiceCredential=true


algorithmSuite=Default />

</security>

</binding>

</wsDualHttpBinding>

</bindings>

<client>

<endpoint
address=net.tcp://localhost:9909/MonitorService/service


binding=netTcpBinding
bindingConfiguration=TcpBinding
contract=IMonitorService


name=TcpBinding>

<identity>

<userPrincipalName
value=ovais />

</identity>

</endpoint>

<endpoint
address=http://localhost:8732/Design_Time_Addresses/MonitorService/


binding=wsDualHttpBinding
bindingConfiguration=WSDualHttpBinding_IMonitorService


contract=IMonitorService
name=WSDualHttpBinding_IMonitorService>

<identity>

<dns
value=localhost />

</identity>

</endpoint>

</client>

</system.serviceModel>

</configuration>

Step 4: Running solution

  1. Install the service and start it
  2. Start the Monitor app and click on connect
  3. Once the service start it will send messages to client and real time logging is achieved.

Using Code First in Entity Framework

Introduction

Generally, entity framework is majorly used by adding an edmx file into your .Net solution and creating tables or dropping tables from existing SQL database. But in certain cases when we are working on large scale applications and having layered architecture with different layers (presentation, service, business and data access) it becomes quite difficult for the developer to make it loosely coupled.

In order to explain, let’s take a simple scenario. Let suppose you have a Web Application with following layers

  1. Web Front End ( ASP.Net MVC)
  2. Service Layer (WCF, Web Services)
  3. Business Layer (Business Managers)
  4. Data Access Layer (Entity Framework)

Web Front End use some models that are bean classes to store data and transmit them the Service layer, service layers are expecting Data Contracts to be passed as parameters and Business Layers actually processes that data and passes it to Data Access Layer to perform to and fro CRUD operations.

Problem

We can make common library project that contains single bean which can be travel from presentation layer to Services and Services to Business layer. Problem arises when we need to pass it to the entity framework. As if we are not using a code first approach we need to map that class to appropriate entity framework entity class. This will increase performance decline and also increase extra effort for developer to provide mappings for all the entities.

Resolution

When you use Code First model you really don’t need to include edmx file into your solution, and you just have to define bean classes or entity classes for each table creating or created already. This helps to place all the classes in one common library that will be referenced by all and will support loosely coupling of layers.

Steps

Steps to Create Entity Framework Code First Model

  1. Create a new Project named as CommonEntities
  2. Add a Library Package Reference of EFCodeFirst using NuGet

  3. Create a new folder named as “Entities” inside your project and define all the entities. Entities contain setter getter properties for all the columns in a table.

For e.g. here are the sample classes


public
class
DocumentColumns

{

[Key]


public
Int32 ColumnId { get; set; }


public
String ColumnName { get; set; }


public
String ColumnType { get; set; }


public
Int32 TypeSize { get; set; }


public
Boolean IsPrimary { get; set; }


public
Boolean AllowNulls { get; set; }


public
Boolean IsMeasure { get; set; }


public
Int32 DocumentId { get; set; }


public
String ColumnSheets { get; set; }

}


public
class
Document

{

[Key]


public
Int32 DocumentId { get; set; }


public
String DocumentPath { get; set; }


public
String DocumentName { get; set; }


public
String DocumentDescription { get; set; }


public
String TableName { get; set; }


public
Boolean IsActive { get; set; }


public
Boolean IsStarSchema { get; set; }


public
String DatabaseName { get; set; }


public
ICollection<DocumentColumns> DocumentColumns { get; set; }

}

Attribute [Key] denotes that particular property is a primary key.

  1. Create a custom context class named as “MyDbContext” which should be derived from System.Data.Entity.DbContext

    public
    class
    SchedulerContext : System.Data.Entity.DbContext

    {


    public
    DbSet<Document> Documents { get; set; }


    public
    DbSet<DocumentColumns> DocumentColumns { get; set; }


    protected
    override
    void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder)

    {

    modelBuilder.IncludeMetadataInDatabase = false;

    }

    }

Here in the above snippet I have overridden the OnModelCreating method and set IncludeMetadataInDatabase = false, this basically not create a new database. This is normally used when you have already an existing database created and you don’t want Entity Framework to create a new database for you.

  1. Add the App.config file in your project and specify the Connectionstring as follows

<connectionStrings>

<add
name=ExcelScheduler.Database.SchedulerContext


connectionString=Data Source=.\sqlexpress;Initial Catalog=SchedulerDB;Integrated Security=True


providerName=System.Data.SqlClient />

</connectionStrings>

This is all done!

Now in order the treat any entity class as WCF data contract you just need to annotate your entity class with [DataContract] attribute and properties with [DataMember] attribute. And same goes if you want to use it with Asp.Net MVC models.

Debugging javascript from Visual Studio

    1. Open the Tools > Internet Options and click on Advanced tab.
    2. Uncheck “Disable script debugging” in the settings list.

    3. Now for any function where you want to debug just specify debugger; like this.

      Example

$(document).ready(function () {


debugger;

     alert(“hello world!”);

}

  • That’s all! Now just run the application in debug mode from visual studio debug it.

Custom Plugin Framework in .Net

Sometimes we came in situation when we need to design an architecture which supports plugin of components at runtime. That facilitates developer to not to compile the main application again and again for new addition of components/plugins and just with a little configuration it should be activated in the application. Therefore, this post shows the plugin framework which helps to plug in components with little configuration.

I took the logger example to develop this framework. In which I will show you how to plug in multiple types of logger into the application. The application is very simple just to show an idea which logs the text from the textbox control on the button click event. System checks the plugins that are available and call the ExecuteTask method of each plugin attached with the application.

Let’s start some coding work.

Create Plugin Framework

  1. Create a new class library project in .net to develop a plugin framework.
  2. Create an interface named IPlugin.cs
  3. Define a property “Name” and method “ExecuteTask” which takes String message as a parameter.

    namespace PluginFramework

    {


    public
    interface
    IPlugin

    {


    String name { get; }


    void ExecuteTask(String message);

    }

    }

  4. Actually the concept behind this framework is that developer does not need to reference new plugins dll or class libary they will just add it in the application configuration file. We will provide an specific section for Plugins. Therefore, we need to create a class which implements IConfigurationSectionHandler and define CreateTask method.
  5. The code snippet for PluginSectionHandler as follows

namespace PluginFramework

{


public
class
PluginSectionHandler : IConfigurationSectionHandler

{


ArrayList plugins = new
ArrayList();


public
object Create(object parent, object configContext, System.Xml.XmlNode section)

{


foreach(XmlNode plugin in section.ChildNodes)

{


object plugObject= Activator.CreateInstance(Type.GetType(plugin.Attributes[“type”].Value));

 plugins.Add(plugObject);

}


return plugins;

}

}

}

Create Custom Plugins

  1. Create another class library project named as “MessagePlugin”. This library contains all types of logger which will be added as a plugin In the main application.
  2. I will create two classes one which write the message in the event log and the other write it in the trace window.
  3. Therefore, create a new TraceMessage class and implement the IPlugin interface.
  4. Define the body for ExecuteTask method as follows.

    public
    class
    TraceMessage : IPlugin

    {


    public
    string name

    {


    get { return
    “Trace Logger”; }

    }


    public
    void ExecuteTask(string message)

    {

    System.Diagnostics.Trace.WriteLine(message);

    }

    }

  5. For EventLogMessage plugin, create a new class and implement the IPlugin interface.
  6. Define the body for ExecuteTask method as follows.

    public
    class
    EventLogMessage : IPlugin

    {


    public
    string name

    {


    get

    {


    return
    “Event Logger”;

    }

    }


    public
    void ExecuteTask(String message)

    {


if (!System.Diagnostics.EventLog.SourceExists(“PluginFramework”))

{

System.Diagnostics.EventLog.CreateEventSource(“PluginFramework”, “MyLog”);

}

System.Diagnostics.EventLog log = new System.Diagnostics.EventLog();

log.Source = “PluginFramework”;

log.WriteEntry(message);

}

}

Create Main Application

  1. Create a Windows Application project and add two controls TextBox and a button on the form.

  2. The concept is that developer will not reference the MessagePlugin library created above in the windows application and he will just define the Type and assembly in the app.config file. When the application starts it will load all the sections added. To do this, we will add app.config file first.
  3. Open the app.config file and place a configsections tag and under configsections tag define a new section tag.

    <configSections>

    <section
    name=plugins
    type=PluginFramework.PluginSectionHandler, PluginFramework/>

    </configSections>

  4. Now add the plugins in the configuration file as below.

<plugins>

<plugin
type=MessagePlugin.EventLogMessage, MessagePlugin />

<plugin
type=MessagePlugin.TraceMessage, MessagePlugin />

</plugins>

Complete app.config will look like as follows.

<?xml
version=1.0
encoding=utf-8 ?>

<configuration>

<configSections>

<section
name=plugins
type=PluginFramework.PluginSectionHandler, PluginFramework/>

</configSections>

<plugins>

<plugin
type=MessagePlugin.EventLogMessage, MessagePlugin />

<plugin
type=MessagePlugin.TraceMessage, MessagePlugin />

</plugins>

</configuration>

  1. Override the onload event of form and load the plugins as follows.


    protected
    override
    void OnLoad(EventArgs e)

    {


    base.OnLoad(e);

     LoadPlugins();

    }


    private
    void LoadPlugins()

    {

     pluginList = (ArrayList)ConfigurationSettings.GetConfig(“plugins”);

    }

  2. Now in the button click event call the plugin’s execute task method.


    private
    void btnLog_Click(object sender, EventArgs e)

    {


    foreach (IPlugin plugin in pluginList)

    {

    plugin.ExecuteTask(textBox1.Text);

    }

    }

  3. Place the MessagePlugins dll or class library in the bin directory of windows application and run the application to test.

For the complete code please email me at ovaismehboob@yahoo.com.