Showing posts with label WCF. Show all posts
Showing posts with label WCF. Show all posts

Tuesday, February 16, 2010

How to use Custom RoleProvider in WCF?

First thing is to add reference to the System.Web.dll assembly to your WCF project. Then create a class which inherits from RoleProvider. You’ll also need to add the System.Web.Security namespace. Then you can use the CTRL+dot trick so that VS generates all the methods for you. You’ll end up with something like this:

public class MyRoleProvider : RoleProvider
{
 
    public override void AddUsersToRoles(string[] usernames, string[] roleNames)
    {
        throw new NotImplementedException();
    }
 
    public override string ApplicationName
    {
        get
        {
            throw new NotImplementedException();
        }
        set
        {
            throw new NotImplementedException();
        }
    }
 
    public override void CreateRole(string roleName)
    {
        throw new NotImplementedException();
    }
 
    public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
    {
        throw new NotImplementedException();
    }
 
    public override string[] FindUsersInRole(string roleName, string usernameToMatch)
    {
        throw new NotImplementedException();
    }
 
    public override string[] GetAllRoles()
    {
        throw new NotImplementedException();
    }
 
    public override string[] GetRolesForUser(string username)
    {
        throw new NotImplementedException();
    }
 
    public override string[] GetUsersInRole(string roleName)
    {
        throw new NotImplementedException();
    }
 
    public override bool IsUserInRole(string username, string roleName)
    {
        throw new NotImplementedException();
    }
 
    public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames)
    {
        throw new NotImplementedException();
    }
 
    public override bool RoleExists(string roleName)
    {
        throw new NotImplementedException();
    }
}

Now, you’ll need to provide actual implementation for all of these methods. That’s up to you.

Next, you need to configure your config file. Add following to the system.web section of your configuration file:

<system.web>
    <roleManager enabled ="true">
 
        <providers>
            <add  name="MyRoleProvider" type="ReducingComplexity.MyRoleProvider, ReducingComplexityRoleProvider"/>
        </providers>
    </roleManager>
</system.web>

Now you’ll need to link this role provider to your services services. You will use serviceBehavior for this. For example, if you have service behavior defined like this:

<behaviors>
    <serviceBehaviors>
        <behavior name="MyServis.MyStandardBehavior">
            <serviceAuthorization roleProviderName="MyRoleProvider" principalPermissionMode="UseAspNetRoles"></serviceAuthorization>
        </behavior>
    </serviceBehaviors>
</behaviors>

Using the <serviceAuthorization>, I set roleProviderName with the name of my role provider as defined under <roleManager> node. Also, principalPermissionMode need to be set to UseAspNetRoles. That’s pretty much it. It’s that simple.

Now it’s possible to use both declarative security framework:

[PrincipalPermission(SecurityAction.Demand,Role = "Customer")]
public List<Order> GetOrders(int customerId)
{
}

or for example Thread.CurrentPrincipal.IsInRole() method.

public List<Order> GetOrders(int customerId)
{
    if (Thread.CurrentPrincipal.IsInRole("Customer")) 
    {
        // get customer orders 
    }
    else 
    {
        // permission denied
    }
}

WCF rocks!!!

Still, there is something I really don’t like. It is the fact that RoleProvider is considered to belong to ASP.NET(hence the need to add reference to System.Web.dll assembly). This is kind of unnatural, and I would like to see the role providers moved to some other assembly, for example System.Security.dll.

Monday, February 15, 2010

WCF and AOP with Castle.DynamicProxy

Managing logging and exception handling in WCF applications can be very time-consuming. Cross-cutting concerns can become a great burden and generate a lot of work for us. Today, I played a little bit with AOP and Castle Dynamic Proxy (DP) library. If you’re not familiar with AOP please take a look at this.

Before I even started with DP, I also considered PostSharp, but eventually I decided to go with DP. Reason: I just don’t like things integrated into VS and doing stuff I cannot fully control. It can be that this is not a legitimate reason, but still:).

I started by adding references to Castle.Core.dll and Castle.DynamicProxy2.dll files. Then I defined my Logging Aspect class

public class LoggingAspect : IInterceptor
{
    #region IInterceptor Members

    public void Intercept(IInvocation invocation)
    {
        Debug.WriteLine(string.Format("The user {0} is calling method {1}.", OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.Name, invocation.Method.Name));
        Debug.WriteLine("Parameters are : ");
        foreach (object argument in invocation.Arguments)
        {
            Debug.WriteLine("Parameter value : " + Convert.ToString(argument));
        }
        invocation.Proceed();
        Debug.WriteLine(string.Format("The calling is complete!"));
    }

    #endregion
}

This code is pretty straightforward. By implementing IInterceptor interface, I print out username of the calling user, the method called, and parameter values. You’ll probably want to write these info into a database or a file in your project. However, this will stands good as an example. Then, to create a proxy for a type:

ProxyGenerator pg = new ProxyGenerator();
var loggingAspect = new LoggingAspect();
var proxy = pg.CreateClassProxy(typeof(MyType), loggingAspect);

That is all I need to do regarding DP itself. Now, I need to integrate this into WCF. Luckily, WCF is very extensible framework. First, I’ll implement IInstanceProvider interface, so that I can control object instances creation. The interface is rather simple, consisting of three methods.

public class MyInstanceProvider : IInstanceProvider
{
    public Type Type { get; private set; }
    public MyInstanceProvider(Type type)
    {
        this.Type = type;
    }

    #region IInstanceProvider Members

    public object GetInstance(System.ServiceModel.InstanceContext instanceContext, System.ServiceModel.Channels.Message message)
    {
        ProxyGenerator pg = new ProxyGenerator();
        var loggingAspect = new LoggingAspect();
        var proxy = pg.CreateClassProxy(this.Type, loggingAspect);
        return proxy;
    }

    public object GetInstance(System.ServiceModel.InstanceContext instanceContext)
    {
        return GetInstance(instanceContext, null);
    }
    public void ReleaseInstance(System.ServiceModel.InstanceContext instanceContext, object instance)
    {
        if (instance is IDisposable)
            ((IDisposable)instance).Dispose();
    }

    #endregion
}

Note that I’m using CreateClassProxy method of ProxyGenerator to create proxies. This requires that methods we want to intercept need to be marked as virtual. Now that I have my IInstanceProvider implemented, I need to hook it up to a service. There are several options for this, but I like using attributes for this. I want to be able to mark my service implementation with some attribute so that all methods on that are intercepted in the same way. To do this I’ll need an attribute that implements IServiceBehavior interface.

public class MyAspectsAttribute : Attribute, IServiceBehavior
{

    #region IServiceBehavior Members

    public void AddBindingParameters(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyDispatchBehavior(ServiceDescription serviceDescription,
        System.ServiceModel.ServiceHostBase serviceHostBase)
    {
        foreach (var dispatcher in serviceHostBase.ChannelDispatchers)
        {
            var cd = dispatcher as ChannelDispatcher;

            foreach (var endpoint in cd.Endpoints)
            {
                endpoint.DispatchRuntime.InstanceProvider = new MyInstanceProvider(serviceDescription.ServiceType);
            }
        }
    }

    public void Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
    {

    }
    #endregion
}

The most important thing here is the ApplyDispatchBehavior method where I set up the instance provider for each endpoint. Next, the only thing left is to mark my service with MyAspects attribute.

[MyAspects]
public class MyGreatService : IMyGreatService 
{
    public virtual string SayHello()
    {
        return "Hello";
    }
}

This way, SayHello() method (and all others marked as virtual) will be intercepted by my LoggingAspect class thus enabling me to centralize my logging code.