Sunday, August 12, 2012

Event Handler in Orchard


Introduction:

The Orchard use the EventBus Pattern to handle the event. In briefly, the EventBus can let you define an EventHandler(It is just a interface with several methods), then if you want to listen to this EventHandler, all you need to do is to inherit this EventHandler interface. If you want to raise this EventHandler, all you need to do is declare the EventHandler as a parameter in the Event Caller constructure. This parameter will be injected automatically if you resolve it with the Autofac. This blog will focue on how your inherited EventHandler will be invoked and how the EventHandler been injected to your Event Class as parameter.



Inject IEventHandler To Event Caller

IEventHandler is the base interface for all the EventHandler. When Orchard web application startup, the OrchardStarter will be used to do most of the registration work.
public static IContainer CreateHostContainer(Action<ContainerBuilder> registrations) {
      var builder = new
ContainerBuilder();
      ...
      builder.RegisterModule(new
EventsModule());
      builder.RegisterType<
DefaultOrchardEventBus>().As<IEventBus>().SingleInstance();

}

internal class EventsModule : Module {
       protected override void Load(
ContainerBuilder builder) {
           builder.RegisterSource(new
EventsRegistrationSource());
           base.Load(builder);
       }
}


In the EventsModule, it Register the EventRegistrationSource to the container. Why using the RegistrationSource? Using RegistrationSource, we can change the registration resolve target for the registration service.
public class EventsRegistrationSource : IRegistrationSource {
public EventsRegistrationSource() {
           _proxyBuilder = new
DefaultProxyBuilder();
       }
       public
IEnumerable<IComponentRegistration> RegistrationsFor(Service service, Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor) {
          
    var serviceWithType = service as IServiceWithType;
           if (serviceWithType == null)
               yield break;

           var serviceType = serviceWithType.ServiceType;
           if (!serviceType.IsInterface || !typeof(
IEventHandler).IsAssignableFrom(serviceType) || serviceType == typeof(IEventHandler))
               yield break;
           var interfaceProxyType = _proxyBuilder.CreateInterfaceProxyTypeWithoutTarget(
               serviceType,
               new
Type[0],
               
ProxyGenerationOptions.Default);

            var rb = RegistrationBuilder
               .ForDelegate((ctx, parameters) => {
                   var interceptors = new
IInterceptor[] { new EventsInterceptor(ctx.Resolve<IEventBus>()) };
                   var args = new object[] { interceptors, null };
                   return
Activator.CreateInstance(interfaceProxyType, args);
               })
               .As(service);

           yield return rb.CreateRegistration();
       }
   }

The RegistrationsFor method will be called by the Autofac internally whenever a registration happened. Autofac will use the return value from RegistrationFor method as the resolve target for the registration type. Orchard use this method to change all the resolve target of IEventHandler to a dynamic created type.
It first check if the current registered type is IEventHandler and is not IEventHandler itself. If yes, then it will create a dynamic type using the Castle.DefaultProxyBuilder. Then it will create a IRegistrationBuilder using a delegate. The delegate will repponse to create the resolve target for the registered IEventHandler type. The resolve target will be the generated dynamic type and the IInterceptor will be  new EventsInterceptor(ctx.Resolve<IEventBus>()).  In another word, all the call to this dynamac type will be redirect to  new EventsInterceptor(ctx.Resolve<IEventBus>()).


Dynamic Type for IEventHandler

The EventInterceptor inherited from IInterceptor which has only one method: void Intercept(IInvocation invocation);Let’s look at the code:
       public EventsInterceptor(IEventBus eventBus) {
           _eventBus = eventBus;
       }

       public void Intercept(
IInvocation invocation) {
           var interfaceName = invocation.Method.DeclaringType.Name;
           var methodName = invocation.Method.Name;

           var data = invocation.Method.GetParameters()
               .Select((parameter, index) => new { parameter.Name, Value = invocation.Arguments[index] })
               .ToDictionary(kv => kv.Name, kv => kv.Value);

           var results = _eventBus.Notify(interfaceName +
"." + methodName, data);

           invocation.ReturnValue = Adjust(results, invocation.Method.ReturnType);
       }

The constructor required a instance of IEventBus which we will discuss later. In the Intercept, it will get the call method information and parameter data, then call IEventBus.Notify with the method name and the data. So when the Event Caller call method of IEventHandler, it eventually call IEventBus->Notify.

IEventBus

In the beginning of this blog, we can see the IEventBus is registered to DefaultOrcharEventBus. Let’s look at the constructor of DefaultOrchardEventBus:
public DefaultOrchardEventBus(Func<IEnumerable<IEventHandler>> eventHandlers, IExceptionPolicy exceptionPolicy) {
           _eventHandlers = eventHandlers;
           _exceptionPolicy = exceptionPolicy;
           T =
NullLocalizer.Instance;
       }
It required a Func<IEnumrable<IEventHanlder>>. According to the Autofac, this type of instance will be composed by Aufofac automatically and when you call this Func, it will return all the IEventHandler that alreadcy been registered into Autofac.  In Orchard, all the class that inherited from IDependency will be registered automatically. IEventHandler is inheried from IDependency. So all the class that inherited from IEventHandler will be registered. So this Func will actually return all the IEventHandler class that exits in the Orchard including your custom event class. Now let’s see what the Notify function doing:
       public IEnumerable Notify(string messageName, IDictionary<string, object> eventData) {
           // call ToArray to ensure evaluation has taken place
           return NotifyHandlers(messageName, eventData).ToArray();
       }

       private
IEnumerable<object> NotifyHandlers(string messageName, IDictionary<string, object> eventData) {
           string[] parameters = messageName.Split(
'.');
           if (parameters.Length != 2) {
               throw new
ArgumentException(T("{0} is not formatted correctly", messageName).Text);
           }
           string interfaceName = parameters[0];
           string methodName = parameters[1];

           var eventHandlers = _eventHandlers();
           foreach (var eventHandler in eventHandlers) {
               
IEnumerable returnValue;
               if (TryNotifyHandler(eventHandler, messageName, interfaceName, methodName, eventData, out returnValue)) {
                   if (returnValue != null) {
                       foreach (var value in returnValue) {
                           yield return value;
                       }
                   }
               }
           }
       }

       private bool TryNotifyHandler(IEventHandler eventHandler, string messageName, string interfaceName, string methodName, IDictionary<string, object> eventData, out IEnumerable returnValue) {
           try {
               return TryInvoke(eventHandler, interfaceName, methodName, eventData, out returnValue);
           }
           catch (
Exception exception) {
               if (!_exceptionPolicy.HandleException(this, exception)) {
                   throw;
               }

               returnValue = null;
               return false;
           }
       }

       private static bool TryInvoke(
IEventHandler eventHandler, string interfaceName, string methodName, IDictionary<string, object> arguments, out IEnumerable returnValue) {
           
Type type = eventHandler.GetType();
           foreach (var interfaceType in type.GetInterfaces()) {
               if (
String.Equals(interfaceType.Name, interfaceName, StringComparison.OrdinalIgnoreCase)) {
                   return TryInvokeMethod(eventHandler, interfaceType, methodName, arguments, out returnValue);
               }
           }
           returnValue = null;
           return false;
       }


The NotifyHandler will get the real interface name and the method name from the argument. Then for all the IEventHandler type in the system, if the type name is the same as interface name in the argument, it will try to invoke the method.
So whenever an Event Caller call the method of a particular IEventHander type method, the call will be invoked on all the type that inheried from this particular type.

Saturday, June 16, 2012

Injection Logger in Orchard


Introduction:

Orchard using Aufofac as DI container. The blog just try to explain one of those usage: Inject Logging. In any system logging is a very basis function and normally when we need to log something, we either create a new Logger instance or get a global instance to do the logging. while, Orchard using a different way to get the Logger instance. Whenever a class requires a Logger instance, all it needs to do is to declare a ILogger property, that’s it. And later, in your class, you can use this property to Logging at anytime. So, how it happening? Who and when this property been set?

Register Logger:

When Orchard web application startup, the OrchardStarter will be used to do most of the registration work.
public static IContainer CreateHostContainer(Action<ContainerBuilder> registrations) {
      var builder = new
ContainerBuilder();
      builder.RegisterModule(new
CollectionOrderModule());
      builder.RegisterModule(new
LoggingModule());

}
The LoggingModule is registered to the Autofac ContainerBuilder. Let’s look at the detail of LoggingModule
public class LoggingModule : Module {
}
It inherites from the Autofac.Module. Autofac.Module provide the method that you can register a group of types in one place.But we only want to register the Logger, why use the Module? The Module provide extra methods that can hooked to the whole registration event so that we can has the chance to inject Logger intance to other object’s property. This method used in LoggingModule is  
protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration) {
           var implementationType = registration.Activator.LimitType;
           // build an array of actions on this type to assign loggers to member properties
           var injectors = BuildLoggerInjectors(implementationType).ToArray();
            // if there are no logger properties, there's no reason to hook the activated event
           if (!injectors.Any())
               return;
           // otherwise, whan an instance of this component is activated, inject the loggers on the instance
           registration.Activated += (s, e) => {
               foreach (var injector in injectors)
                   injector(e.Context, e.Instance);
           };

}
AttachToComponentRegistration will be used by the Autofac to attach to both the existing registered components and the  future components that will be registered to this ContainerBuilder. In the code with red color, we can see when a component will be activated(or resolved), we will run each injector to this new created instance. What is the injector? Let’s see the detail of BuillLoggerInjectors
private IEnumerable<Action<IComponentContext, object>> BuildLoggerInjectors(Type componentType) {
           // Look for settable properties of type "ILogger"
           var loggerProperties = componentType
               .GetProperties(
BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.Instance)
               .Select(p => new {
                   PropertyInfo = p,
                   p.PropertyType,
                   IndexParameters = p.GetIndexParameters(),
                   Accessors = p.GetAccessors(false)
               })
               .Where(x => x.PropertyType == typeof(
ILogger)) // must be a logger
               .Where(x => x.IndexParameters.Count() == 0) // must not be an indexer
               .Where(x => x.Accessors.Length != 1 || x.Accessors[0].ReturnType == typeof(void)); //must have get/set, or only set

           // Return an array of actions that resolve a logger and assign the property
           foreach (var entry in loggerProperties) {
               var propertyInfo = entry.PropertyInfo;

               yield return (ctx, instance) => {
                   string component = componentType.ToString();
                   var logger = _loggerCache.GetOrAdd(component, key => ctx.Resolve<
ILogger>(new TypedParameter(typeof(Type), componentType)));
                   propertyInfo.SetValue(instance, logger, null);
               };
           }
       }

In this method, it first find all the properties that type is ILogger and is not indexer and it can  be set. Next for each of these properties, it will create a Action that set the property to ILogger instance that from local cache or resolve from the context. In the Load method of LoggingModule, it register the LoggerFactory and the ILogger
protected override void Load(ContainerBuilder moduleBuilder) {
           // by default, use Orchard's logger that delegates to Castle's logger factory
           moduleBuilder.RegisterType<
CastleLoggerFactory>().As<ILoggerFactory>().InstancePerLifetimeScope();
moduleBuilder.RegisterType<
OrchardLog4netFactory>().As<Castle.Core.Logging.ILoggerFactory>().InstancePerLifetimeScope();
           // call CreateLogger in response to the request for an ILogger implementation
           moduleBuilder.Register(CreateLogger).As<
ILogger>().InstancePerDependency();
}

We can see register ILogger using a delegate. Why? Because we don’t want to create Logger for each activated instance, for the same type of instance, we just want to use the same Logger instance.
private static ILogger CreateLogger(IComponentContext context, IEnumerable<Parameter> parameters) {
           // return an ILogger in response to Resolve<ILogger>(componentTypeParameter)
           var loggerFactory = context.Resolve<
ILoggerFactory>();
           var containingType = parameters.TypedAs<
Type>();
           return loggerFactory.CreateLogger(containingType);
}

We can see the loggerFactory.CreateLogger passed in the type of the current activated type.

Monday, January 16, 2012

Open Access 2003 under Access 2007 with mdw file

When you open the Access 2003 file using Access 2007, it will using the default mdw file and you lost all of your use security. So what you need to do is create a shortcut and point it to your mdb file and the mdw file like "path to mdb file" /wrkgrp "path to secure.mdw"

After that, you can verify the mdw file is correct loaded by press Ctrl-G and enter the ?SysCmd(acSysCmdGetWorkgroupFile) into to vb immediate windows.

Sunday, July 3, 2011

Enable Https for WCF

To enable Https for WCF, you need to change the config in the service site. For host in IIS, you need to make sure do not assign the name to bindings/[binding type]/binding and do not assign binding name in services/service/endpoint. Below is the sample:

<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="HttpsBehavior" >
<serviceMetadata httpsGetEnabled="true" httpGetEnabled="true" policyVersion="Policy12"/>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="TestService" behaviorConfiguration="HttpsBehavior" >
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange" />
<endpoint
address=""
binding="basicHttpBinding" "No Bindding Name here"
contract="mProductive.PortalAdmin.WebSite.IWebPurchase"
/>
</service>
</services>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" >
<baseAddressPrefixFilters>
<add prefix="http://localhost/"/>
</baseAddressPrefixFilters>
</serviceHostingEnvironment>
<bindings >
<basicHttpBinding>
<binding "No Bindding Name here">
<security mode="Transport">
<transport clientCredentialType="None"/></security>
</binding>
</basicHttpBinding>
</bindings>
</system.serviceModel>

Tuesday, November 3, 2009

supportsMaintainScrollPositionOnPostback On Chrome

Add a new file called others.browser to the app_browser folder. This can also fix the asp.net Menu control under chrome. The file content as below:
<browsers>
<browser id="Safari3" parentID="Safari1Plus">
<identification>
<userAgent match="Safari/\d+\.\d+" />
</identification>
<capture>
<userAgent match="Version/(?'version'\d+\.\d+)" />
</capture>
<capabilities>
<capability name="browser" value="Safari3" />
<capability name="version" value="${version}" />
</capabilities>
<controlAdapters>
<adapter controlType="System.Web.UI.WebControls.Menu"
adapterType="" />
</controlAdapters>
</browser>
<browser id="GoogleChrome" parentID="Safari3">
<identification>
<userAgent match="Chrome/(?'version'\d+\.\d+)" />
</identification>
<capabilities>
<capability name="browser" value="Googlebot" />
<capability name="supportsMaintainScrollPositionOnPostback" value="true" />
</capabilities>
</browser>
</browsers>

Wednesday, October 28, 2009

Clear ASP.Net Session from another ASP site

We have a 2 web app under our web site, one is asp.net and another one is asp. After user logout from the ASP web app, we need to make sure the ASP.Net site also been logout.

First we try to use Response.Cookie to delete the ASP.NET_SessionId cookie which issued by ASP.Net, but ASP will automatically encode the ASP.NET_SessionId to ASP%2ENET%5FSessionId which will add a new cookie.

So finally we use the Response.AddHeader "Set-Cookie","ASP.NET_SessionId=deleted;Path=/" to solve the problem

Write Cookie without Encode from ASP

In ASP, if you using Server.Cookie to add or change any cookie, the name and value of the cookie will be urlencode by ASP automatically. So if you call Server.Cookie("my.cookie") = "my_cookie", then on the browser, you will get my%2Ecookie = my%5Fcookie.

So you can use Response.AddHeader "Set-Cookie", "my.cookie=my_cookie" and you will get exact the name and value on your browser.