TopMenu

Using IOperationInvoker in WCF for Global exception handling and logging

There are several ways to implement the Global Exception handling in WCF for e.g. using a  IErrorHandler (The best way to handle the uncaught exceptions) or creating your own Façade for calling all service methods. In this article we’ll discuss about an Interceptor IOperationInvoker that can be used before and after activity when a service actually calls it’s operations. There are several things you can perform at this stage like Logging, Tracing or Handling the Exception(specially Unhandled Exceptions).

First we’ll start to look at high level of the picture where the Operation invoker actually stands when a client make a service method call. Below diagram is showing a picture of the same.

IOperationInvoker WCF cshandler.com

So lets create a WCF service project. (Learn how to create and consume WCF service). After adding the project, we need to add some operation in the service so for e.g. our service operation is GetParseData(). So it can look something like this(as generated from Project template).

IServiceContract:

[OperationContract]
string GetParseData(string value)


Service.cs


public string GetParseData(string value)
{
return string.Format("You entered: {0}", value);
}

To get some exceptions we’ll a custom logic in the Implementation of GetParseData(). So it can look something like this.

public string GetParseData(string value)
{
// check if value is alphabets/Numeric
if (string.IsNullOrEmpty(value))
{
throw new ArgumentException("Method parameter value can not be null or empty");
}

// split the value if it contains spaces and return first two words
var stringArray = value.Split(' ');

// This will/may cause an Unhandled exception for OutOfIndex in case of single word is passed.
return string.Format("{0}_{1}_{2} ..", stringArray[0], stringArray[1], stringArray[2]);
}


Here in this method we have introduced some known and unhandled exception. To demonstrate the logging and Global exception handling we’ll now create a class that will Implement the IOperationInvoker interface.


/// <summary>
/// Global error handler of service operations using IOperationInvoker
/// </summary>
public class ErrorHandlingLoggingOperationInvoker : IOperationInvoker
{
private readonly ILog logger;

private IOperationInvoker invoker;

private string operationName;



public ErrorHandlingLoggingOperationInvoker(IOperationInvoker baseInvoker, DispatchOperation operation)
{
this.invoker = baseInvoker;
this.operationName = operation.Name;
XmlConfigurator.Configure();
logger = LogManager.GetLogger("serviceLogger");
}



public bool IsSynchronous
{
get
{
return true;
}
}



public object[] AllocateInputs()
{
return this.invoker.AllocateInputs();
}



//This is our intent method to intercept the request.
public object Invoke(object instance, object[] inputs, out object[] outputs)
{
logger.InfoFormat("Start command operation:{0}", this.operationName);

object result = null;

try
{
result = this.invoker.Invoke(instance, inputs, out outputs);
}
catch (Exception exception)
{
logger.Error("Unhandled Exception: ", exception);
outputs = new object[] { };

throw new FaultException(new FaultReason(exception.Message));
}

logger.InfoFormat("End command operation:{0}", this.operationName);

return result;
}



public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
{
throw new Exception("The operation invoker is not asynchronous.");
}



public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
{
throw new Exception("The operation invoker is not asynchronous.");
}
}



In this implementation of IOperationInvoker we will only focus on the Invoke() method to log the request begin and request end also a Try Catch block is placed on the invoke statement so that we can capture any unhandled exception and log it in the first place with all details. And we’re not sending the complete exception to the client but a custom FaultException with less details or a message.



Now the invoker is ready but how to attached this Invoker/Dispatcher to our service. For this we’ll implement the IOperationBehavior first to attach the invoker with default operation behaviors.


/// <summary>
/// Bhavior defined for global exception handler
/// </summary>
public class GlobalExceptionHandlerBehavior : IOperationBehavior
{
public void Validate(OperationDescription operationDescription)
{
return;
}



public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{// Here we have added our invoker to the dispatch operation dispatchOperation.Invoker = new ErrorHandlingLoggingOperationInvoker(dispatchOperation.Invoker, dispatchOperation);
}



public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
{
return;
}



public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
{
return;
}
}



Now we have our invoker as Operation behavior.  Now we need to implement the IServiceBehavior and we’re done. Then you can directly use this behavior via the binding configuration directly using extensions. See here How to add the extended behavior in the service from configuration file.


But here we’ll create our Custom Attribute class and will use it in the code directly as an Attribute on service class. To create an Attribute for service behavior we need to inherit the Attribute class in our CustomAttribute implmenetation with IServiceBehavior .


Here the code:


/// <summary>
/// Attribute class for applying custom service behavior on Service
/// </summary>
public class ExceptionHandlerLoggerBehaviorAttribute : Attribute, IServiceBehavior
{
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
return;
}

public void AddBindingParameters(
ServiceDescription serviceDescription,
ServiceHostBase serviceHostBase,
Collection<ServiceEndpoint> endpoints,
BindingParameterCollection bindingParameters)
{
return;
}

public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (ServiceEndpoint endpoint in serviceDescription.Endpoints)
{
foreach (OperationDescription operation in endpoint.Contract.Operations)
{
IOperationBehavior behavior = new GlobalExceptionHandlerBehavior();
operation.Behaviors.Add(behavior);
}
}
}
}


Here we are actually applying the behavior to the end points. which in turn doing the same as we do apply behavior via the configuration file with each EndPoint. So our Attribute class is ready, we're going to tell the Service calls that you have a custom behavior to handle the global exception.


[ExceptionHandlerLoggerBehavior]
public class Service1 : IService1
{
public string GetParseData(string value)
{
// check if value is alphabets/Numeric
if (string.IsNullOrEmpty(value))
{
throw new ArgumentException("Method parameter value can not be null or empty");
}

// split the value if it contains spaces and return first two words
var stringArray = value.Split(' ');

// This will/may cause an Unhandled exception for OutOfIndex in case of single word is passed.
return string.Format("{0}_{1}_{2} ..", stringArray[0], stringArray[1], stringArray[2]);
}
}


Now we’ll create a client and call the service method. To create a client simple host the service in IIS express and find the service reference via service reference dialog box. We’ll simply use the Console application as a client.


public static void Main(string[] args)
{
ServiceReference1.Service1Client client = new Service1Client();
try
{
string value = client.GetParseData("somevalue");
Console.WriteLine(value);
}
catch (FaultException ex)
{
Console.WriteLine("========= Error ==========");
Console.WriteLine("{0}", ex.Message);
}

Console.Read();
}


so run the client with different values. For e.g. call the method GetParseData()


i) “some values are valid values” (will not throw exception)



ii) “somevalue” (will throw exception)


image


Let’s take a look at the log file. How the logs are getting produced from the our custom Interceptor.


2013-06-24 14:09:35,339 [6] INFO  serviceLogger - Start command operation:GetParseData
2013-06-24 14:09:35,353 [6] INFO serviceLogger - End command operation:GetParseData
2013-06-24 14:09:57,714 [6] INFO serviceLogger - Start command operation:GetParseData
2013-06-24 14:09:57,716 [6] ERROR serviceLogger - Unhandled Exception:
System.IndexOutOfRangeException: Index was outside the bounds of the array.
at CShandler.SampleWCFServiceApplication.Service1.GetParseData(String value) in c:\Users\achoudhary\Documents\Visual Studio 2012\Projects\WpfApplication1\CShandler.SampleWCFServiceApplication\Service1.svc.cs:line 26
at SyncInvokeGetParseData(Object , Object[] , Object[] )
at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
at CShandler.SampleWCFServiceApplication.ErrorHandlingLoggingOperationInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs) in c:\Users\achoudhary\Documents\Visual Studio 2012\Projects\WpfApplication1\CShandler.SampleWCFServiceApplication\ErrorHandlingLoggingOperationInvoker.cs:line 85


Hope you enjoyed the article. Please leave a comment or suggestion.

Handle partial content request in WebAPI Aspnet

In this post we’ll talk about downloading the full and partial content of a file from server. Then we’ll see if you can achieve it via WebAPI. Before we jump to the main discussion we’ll look at some basic things. So lets take a simple case when you try to download a file from server what actually a header contains in request and response. For e.g. you want to download a file say, data.zip. Before sending the request you can run the fiddler to trace your request and response.
When you send the request first time you’ll see the Request head will contain information something like this:
GET /files/data.zip HTTP/1.1
Accept-Language: en/us,en
User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64; rv:21.0) Gecko/20100101 Firefox/21.0


now if you check the response then It’ll look something like below:

HTTP/1.1 200 OK
Content-Type: application/x-zip-compressed
Last-Modified: Mon, 18 June 2013 07:15:20 GMT
Accept-Ranges: bytes
ETag: "e2827cfd8e57ce1:0"
Server: Microsoft-IIS/8.0
Date: Mon, 17 Jun 2013 09:01:22 GMT
Content-Length: 62887922


So if you want to know that if you server is available to serve the partial content then have look at the attribute:

Accept-Ranges: bytes


If this attribute is present with value bytes that means client can request the partial content to download. If this attribute no present in the response or have a value none that means server doesn’t accept the partial content request.

Partial content request headers

Let’s take a look at the partial content headers how they look like when a request is made for the same.

GET /files/data.zip HTTP/1.1
Accept-Language: en/us,en
User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64; rv:21.0) Gecko/20100101 Firefox/21.0
If-Match: "dfTGdsdIofQXrAY3ZddfSd=="
Range: bytes=22234-


Here if you observe the Range header have value specified in Bytes with –. It basically follows the format e.g. Range:{from}-{To}. if nothing is specified in the To part then it’ll read the file to the end and write it in the response. otherwise if a value is mentioned then It’ll read that portion only. Now let’s look at the response of this request.

HTTP/1.1 206 OK
Content-Range: bytes 22234-62887922/62887923
Content-Length: 62887922
Content-Type: application/x-zip-compressed
Last-Modified: Mon, 18 June 2013 09:15:20 GMT
ETag: "dfTGdsdIofQXrAY3ZddfSd=="
Accept-Ranges: bytes
Binary content of data.zip from byte 500,001 onwards...


If you want to learn more about the range specific request in HTTP protocol you can take a look at the HTTP Spec.

Now, Lets get back to the business why we are discussing all this stuff. I have a Asp.net MVC WebAPI which is actually serving me the file based on the query parameters. Now in this case the scenario will change. We can not send the partial request directly to the Controller. If we do need to write the custom code to handle the partial requests. If you’re thinking to write the HttpHandlers at this moment then I should tell you that “Controller are new Handlers in WebAPI”. Jeff Fritz wrote a nice article on this discussion.

So first you can start creating a simple Asp.net WebAPI project. Let say add an DownloadController in the contollers folder. We have a method say DownloadFile in it. So when we send a request to download a file then It’ll look something like this. This below sample is just reading the file from disk and returning the complete file. 

public class DownloadController : ApiController
{
    public HttpResponse DownloadFile(string fileName)
    {
        // put your logic for reading the file from disk and return
        HttpResponseMessage result = null;
        var fullFilePath = Path.Combine(this.packageDirectoryFilePath, fileName);

        // Get the complete file
        FileStream sourceStream = File.Open(fullFilePath, FileMode.Open, FileAccess.Read, FileShare.Read);
        BufferedStream bs = new BufferedStream(sourceStream);

        result = new HttpResponseMessage(HttpStatusCode.OK);
        result.Content = new StreamContent(bs);

        result.Content.Headers.ContentType = new MediaTypeHeaderValue(MimeType);
        result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
            {
                FileName = fileName
            };

        return result;
    }
}


So to send the partial content request you need send a partial content request something. I’ve wrote a custom function to create and send a partial content request or so to say Range specific request.

Client_Program.cs

private static void DownloadFileWithRangeSpecificRequests(string sourceUrl, string destinationPath)
        {
            long existLen = 0;
            System.IO.FileStream saveFileStream;
            if (System.IO.File.Exists(destinationPath))
            {
                System.IO.FileInfo fINfo =
                    new System.IO.FileInfo(destinationPath);
                existLen = fINfo.Length;
            }
            if (existLen > 0)
                saveFileStream = new System.IO.FileStream(destinationPath,
                                                          System.IO.FileMode.Append, System.IO.FileAccess.Write,
                                                          System.IO.FileShare.ReadWrite);
            else
                saveFileStream = new System.IO.FileStream(destinationPath,
                                                          System.IO.FileMode.Create, System.IO.FileAccess.Write,
                                                          System.IO.FileShare.ReadWrite);
 
            System.Net.HttpWebRequest httpWebRequest;
            System.Net.HttpWebResponse httpWebResponse;
            httpWebRequest = (System.Net.HttpWebRequest) System.Net.HttpWebRequest.Create(sourceUrl);
            httpWebRequest.AddRange((int) existLen);
            System.IO.Stream smRespStream;
            httpWebResponse = (System.Net.HttpWebResponse) httpWebRequest.GetResponse();
            smRespStream = httpWebResponse.GetResponseStream();
            var abc = httpWebRequest.Timeout;
 
            smRespStream.CopyTo(saveFileStream);
            saveFileStream.Close();
        }


This will actually read the file from file system and if it’s not fully downloaded then send the request from where the last byte of the file. So if you try to run the application with the default downloader and the client you’ll always get the complete file. Since the DownloadController doesn’t know about the request if it’s a Range specific. So let’s modify the controller and put some checks to receive the RangeSpecific requests and treat them specially.

Update DownloadController.cs

/// <summary>
/// Gets the file from server.
/// </summary>
/// <param name="fileName">Name of the file.</param>
/// <returns>response content of file</returns>
public HttpResponseMessage DownloadFile(string fileName)
{
    this.LogRequestHttpHeaders(this.logFilePath, Request);

    HttpResponseMessage result = null;
    var fullFilePath = Path.Combine(this.packageDirectoryFilePath, fileName);

    if (Request.Headers.Range == null || Request.Headers.Range.Ranges.Count == 0 ||
        Request.Headers.Range.Ranges.FirstOrDefault().From.Value == 0)
    {
        // Get the complete file
        FileStream sourceStream = File.Open(fullFilePath, FileMode.Open, FileAccess.Read, FileShare.Read);
        BufferedStream bs = new BufferedStream(sourceStream);

        result = new HttpResponseMessage(HttpStatusCode.OK);
        result.Content = new StreamContent(bs);

        result.Content.Headers.ContentType = new MediaTypeHeaderValue(MimeType);
        result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
            {
                FileName = fileName
            };
    }
    else
    {
        // Get the partial part
        var item = Request.Headers.Range.Ranges.FirstOrDefault();
        if (item != null && item.From.HasValue)
        {
            result = this.GetPartialContent(fileName, item.From.Value);
        }
    }

    this.LogResponseHttpHeaders(this.logFilePath, result);

    return result;
}

/// <summary>
/// Reads the partial content of physical file.
/// </summary>
/// <param name="fileName">Name of the file.</param>
/// <param name="partial">The partial.</param>
/// <returns>response content of the file</returns>
private HttpResponseMessage GetPartialContent(string fileName, long partial)
{
    var fullFilePath = Path.Combine(this.packageDirectoryFilePath, fileName);
    FileInfo fileInfo = new FileInfo(fullFilePath);
    long startByte = partial;

    Action<Stream, HttpContent, TransportContext> pushContentAction = (outputStream, content, context) =>
        {
            try
            {
                var buffer = new byte[65536];
                using (var file = File.Open(fullFilePath, FileMode.Open, FileAccess.Read, FileShare.Read))
                {
                    var bytesRead = 1;
                    file.Seek(startByte, SeekOrigin.Begin);
                    int length = Convert.ToInt32((fileInfo.Length - 1) - startByte) + 1;

                    while (length > 0 && bytesRead > 0)
                    {
                        bytesRead = file.Read(buffer, 0, Math.Min(length, buffer.Length));
                        outputStream.Write(buffer, 0, bytesRead);
                        length -= bytesRead;
                    }
                }
            }
            catch (HttpException ex)
            {
                this.LogException(ex);
            }
            finally
            {
                outputStream.Close();
            }
        };

    HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.PartialContent);
    result.Content = new PushStreamContent(pushContentAction, new MediaTypeHeaderValue(MimeType));
    result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
        {
            FileName = fileName
        };

    return result;
}


So Now we have added  some conditions to check if a request is range specific or it’s a full content request. To server the partial content I’ve wrote a custom function GetPartialContent() which take the file name and the startByte as the argument. Also we have used the PushStreamContent to write the content to the response.

Now your WebAPI is ready to serve the content with Range specific request.

But to tell you the update this case is already been taken in to account my Microsoft Asp.net team and they’ve included the Byte specific request handlers in the NightlyBuilds which are available via Nugets. But I’ve to write it as updating the production with latest Pre-release could be an impact when RTM would be available.

Complete source code:

DownloadController.cs


Client.cs

Rhino MockRepository concrete vs static usage

In this article we’ll see difference between usage of MockRepository object initialization vs using Static functions to create and setup the mock/stubs. In the initial version of Rhino mocks it was the object which was being used but once the DynamicMock and Strick mocks becomes popular, new static function were being introduced in it’s release 3.5.

Readers Note: I’m expecting that if you’re reading this article you’re already familiar with Unit testing and requirements of Mock objects with basics of Rhino mocks.

Using the MockRepository concrete:

When we use the repository object to create and setup the expectations like:

var mocks = new MockRepository();


in this case when we start creating and setting up the expectations. The object automatically goes into the Record mode. and it won’t changes it’s state until you call PlayBack() or RelayAll() on repository object so to use the concrete object of repository you’ll be using it like below:


public void When_user_forgot_password_should_save_user()
{
var mocks = new MockRepository();
var mockUserRepository = mocks.DynamicMock<IUserRepository>();
var stubbedSmsSender = mocks.GenerateStub<ISmsSender>();

using(mocks.Record())
{
var theUser = new User{HashedPassword = "this is not hashed password"};

mockUserRepository.Stub(x => x.GetUserByName("cshandler")).Return(theUser);

mockUserRepository.Expect( x => x.Save(theUser) );
}

using(mocks.Playback())
{

var controllerUnderTest = new LoginController(mockUserRepository, stubbedSmsSender);

controllerUnderTest.ForgotMyPassword("cshandler");
}
}


Here we can see the Record block and Playback block are seperated out to keep the repository object separate from default behavior.


Now If you don’t want to use these block then the Static functions of MockRepository class will be your friend. Let’s have a look at the below snippet:


public void When_user_forgot_password_should_save_user()
{
var mockUserRepository = MockRepository.GenerateMock<IUserRepository>();
var stubbedSmsSender = MockRepository.GenerateStub<ISmsSender>();

var theUser = new User{HashedPassword = "this is not hashed password"};

mockUserRepository.Stub(x => x.GetUserByName("cshandler")).Return(theUser);

mockUserRepository.Expect( x => x.Save(theUser) );

var controllerUnderTest = new LoginController(mockUserRepository, stubbedSmsSender);

controllerUnderTest.ForgotMyPassword("cshandler");

mockUserRepository.VerifyAllExpectations();
}


This is quite easy to write and easily readable. Though there are differences between the usage.


If you are using the Instance then you don’t need to call the VerfiyAllExpectations() method while in case of without using the instance It is required to call this function explicitly. These two ways of using the mock/stub with Rhino mocks are standard. So be careful when you’re choosing any approach. Do not mix up both methodology or you’ll end up getting unexpected errors. I’m sharing a small check list which might help you when you start working with Rhino mocks.


Tips to remember while using Rhino mocks:


1. Stub() defines the behavior for stubbed object.
2. Expect() defines the behavior and the expectation for mocked object.
3. Follow the principle of "Test only one thing per test".
4. mockrepositoryObject doesn't stop recording until you call ReplayAll.
Try using repositoryInstance.PlayBack();
Code:

using (repository.Playback())
{
}
5. Call repository.VerfiyAll() in the end.
6. Use strickMock for defined behavior and strict expectation for method and properties call.
7. use DynamicMock for object behavior testing for a data supplied.


More on Stub() and Mock(): A mock is an object that we can set expectations on, and which will verify that the expected actions have indeed occurred. A stub is an object that you use in order to pass to the code under test. You can setup expectations on it, so it would act in certain ways, but those expectations will never be verified.
A stub's properties will automatically behave like normal properties, and you can't set expectations on them.If you want to verify the behavior of the code under test, you will use a mock with the appropriate expectation, and verify that. If you want just to pass a value that may need to act in a certain way, but isn't the focus of this test, you will use a stub.


IMPORTANT: A stub will never cause a test to fail. (see release notes 3.5 Rhino mocks)


8. Use following statement for debugging and detailed logging


RhinoMocks.Logger = new TextWriterExpectationLogger(Console.Out);




References: http://ayende.com/wiki/Rhino+Mocks+3.5.ashx

Enum operations for name value attributes

Enumerations are basically used to write clean and readable code for a set of constant values. I won’t be explaining about the basics of Enumeration but going to the next level we’ll see in this article how to manipulate the values, name and attributes using the Reflection at run time.

First let’s take a simple Enum. We’ll be using it through out the article for demo:

public enum TestEnum
{
[Description("Undefined Enum")]
Undefined = 0
[Description("Enumeration 1")]
Enum1 = 1,
[Description("Enumeration 2")]
Enum2 = 2,
}




Here are the list of operation with snippets that we can perform in order to use the TestEnum in various ways:


Get the name of Enum:


Console.WriteLine(TestEnum.Enum1.ToString());


Get the value of Enum:


Console.WriteLine(TestEnum.Enum1.ToString("d"));


The special thing you’ll see here is we have just mentioned the string formatter “d” and it’ll automatically fetch the value of Enum insteat of printing it’s name. So you don’t have to do explicit conversion like (int)TestEnum.Enum1 to get the value.


Get the description value on Enum: In our TestEnum we have provided some description over the Enum. So when required you can fetch the description attribute value if required. Below is the snippet for getting the value of description attribute using Reflection:


Snippet:


/// <summary>
/// Gets the error message attribute value.
/// </summary>
/// <param name="enumerationType">Type of the enumeration.</param>
/// <returns>
/// value of the attribute
/// </returns>
public static string GetDescriptionOfEnum(this Enum enumerationType)
{
Type type = enumerationType.GetType();

MemberInfo[] memInfo = type.GetMember(enumerationType.ToString());

if (memInfo.Length > 0)
{
object[] attributes = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);

if (attributes.Length > 0)
{
return ((DescriptionAttribute)attributes[0]).Description;
}
}

return enumerationType.ToString();
}
This snippet is an extension method that will search for the attribute and if it doesn’t find any then simply returning the name of the enumerationType.

 

Usage:

Console.WriteLine(TestEnum.Enum1.GetDescriptionOfEnum());


Get the Enum from string name: This is the case where you want to fetch the enum based on the String name provided for that Enum. for e.g. we have TestEnum.Enum1 is an enum and I want to get this by the string name “Enum1”. I’ve used reflection to get the name compare and return the Enum. Also additionally this snippet will also match the given string with attribute value on the enum and return the Enum if it matches. Here the code snippet for it.


Snippet:





public static TestEnum GetEnumByNameOrDescription(string parameterName)
{
var testEnum = TestEnum.Undefined;

foreach (string item in Enum.GetNames(typeof(TestEnum)))
{
testEnum =
string.Equals(item, parameterName, StringComparison.InvariantCultureIgnoreCase) ||
string.Equals(
((TestEnum)Enum.Parse(typeof(TestEnum), item, true)).GetDescriptionOfEnum(),
parameterName, StringComparison.InvariantCultureIgnoreCase)
? (TestEnum)Enum.Parse(typeof(TestEnum), item, true)
: TestEnum.Undefined;

if (testEnum != TestEnum.Undefined)
break;
}

if (testEnum == TestEnum.Undefined)
{
throw new Exception(
string.Format(
"Failed to cast string value {0} " +
"to enum type.",
parameterName));
}

return testEnum;
}

 

Usage:



// get enum by name
var enum1 = Extension.GetEnumByNameOrDescription("Enum1")
// get enum by description
var enum1 = Extension.GetEnumByNameOrDescription("Enumeration 1"))

 

Get Enum by value:

Let suppose you want to get the Enum by it’s value. for e.g. we have Enum2 with value 2. So if you want to get the Enum2 type by value 2 you can do it as shown in below example.

Snippet:

public static TestEnum GetEnumByValue(int value)
{
var testEnum = TestEnum.Undefined;

foreach (int item in Enum.GetValues(typeof(TestEnum)))
{
testEnum = item == value
? (TestEnum)Enum.Parse(typeof(TestEnum), value.ToString("d"), true)
: TestEnum.Undefined;

if(testEnum != TestEnum.Undefined)
break;
}

if (testEnum == TestEnum.Undefined)
{
throw new Exception(
string.Format(
"Failed to cast int value {0} " +
"to enum type.",
value));
}

return testEnum;
}


Usage:

var enum2 = Extension.GetEnumByValue(2);


The Extension is a static class I’ve created to keep these utility methods.

 

Here’s the complete code for the above article:

 


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
namespace Demo.EnumOperation
{
/// <summary>
/// The test Enum
/// </summary>
public enum TestEnum
{
[Description("Undefined Enum")]
Undefined = 0,
[Description("Enumeration 1")]
Enum1 = 1,
[Description("Enumeration 2")]
Enum2 = 2,
}

/// <summary>
/// Contains all the extension/utility method
/// </summary>
public static class Extension
{
public static TestEnum GetEnumByValue(int value)
{
var testEnum = TestEnum.Undefined;

foreach (int item in Enum.GetValues(typeof(TestEnum)))
{
testEnum = item == value
? (TestEnum)Enum.Parse(typeof(TestEnum), value.ToString("d"), true)
: TestEnum.Undefined;

if (testEnum != TestEnum.Undefined)
break;
}

if (testEnum == TestEnum.Undefined)
{
throw new Exception(
string.Format(
"Failed to cast int value {0} " +
"to enum type.",
value));
}

return testEnum;
}

public static TestEnum GetEnumByNameOrDescription(string parameterName)
{
var testEnum = TestEnum.Undefined;

foreach (string item in Enum.GetNames(typeof(TestEnum)))
{
testEnum =
string.Equals(item, parameterName, StringComparison.InvariantCultureIgnoreCase) ||
string.Equals(
((TestEnum)Enum.Parse(typeof(TestEnum), item, true)).GetDescriptionOfEnum(),
parameterName, StringComparison.InvariantCultureIgnoreCase)
? (TestEnum)Enum.Parse(typeof(TestEnum), item, true)
: TestEnum.Undefined;

if (testEnum != TestEnum.Undefined)
break;
}

if (testEnum == TestEnum.Undefined)
{
throw new Exception(
string.Format(
"Failed to cast string value {0} " +
"to enum type.",
parameterName));
}

return testEnum;
}

/// <summary>
/// Gets the error message attribute value.
/// </summary>
/// <param name="enumerationType">Type of the enumeration.</param>
/// <returns>
/// value of the attribute
/// </returns>
public static string GetDescriptionOfEnum(this Enum enumerationType)
{
Type type = enumerationType.GetType();

MemberInfo[] memInfo = type.GetMember(enumerationType.ToString());

if (memInfo.Length > 0)
{
object[] attributes = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);

if (attributes.Length > 0)
{
return ((DescriptionAttribute)attributes[0]).Description;
}
}

return enumerationType.ToString();
}
}

/// <summary>
/// Main program
/// </summary>
class EnumOperations
{
static void Main(string[] args)
{
var enum2 = Extension.GetEnumByValue(2);

var enum1 = Extension.GetEnumByNameOrDescription("Enum1");
var enumTest1 = Extension.GetEnumByNameOrDescription("Enumeration 1");
Console.WriteLine(Extension.GetEnumByNameOrDescription("Enum1").ToString("d"));
Console.WriteLine(TestEnum.Enum1.ToString("d"));
Console.WriteLine(TestEnum.Enum1.GetDescriptionOfEnum());

Console.ReadKey();
}
}
}

Expanding the probing domains of running assembly

We all know about shared assemblies, and usually we want to keep them in the GAC. But is it always the solution for shared assemblies. Let’s take an example if you want to create an application which accepts plugins. So when you install the plugin with the application where you will going to install the assemblies of plugin and so that It can be easily searched by the Application. There are few option that I know:

i) Copying the plugin assemblies to the private bin path of the application.

ii) Putting the plugin assemblies in the GAC. (Not a good idea) as only a single application going to use that so this might not be the best solution.

ii) Expanding the probing domain and creating an external folder as a part of private bin path. Put the plug in assembly there. Now I’ll tell you how you can do it?

Previously, I was only aware about the probing domain searches the required assembly in the Private bin and GAC for e.g. you’re loading them dynamically.

To add any custom folder to the probing domain of the application just add below entry to the configuration file.

<!-- Adding custom folder of the Private bin to default probing domains -->
<runtime>
  <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
    <probing privatePath="c:\plugins;"/>
  </assemblyBinding>
</runtime>

And you’re done. Next time you will be keep the plugin assemblies separate from the core assembly of the application.