开发者

Windsor IHandlerSelector in RIA Services Visual Studio 2010 Beta2

I want to implement multi tenancy using Windsor and i don't know how to handle this situation:

i succesfully used this technique in plain ASP.NET MVC projects and thought incorporating in a RIA Services project would be similar.

So i used IHandlerSelector, registered some components and wrote an ASP.NET MVC view to verify it works in a plain ASP.NET MVC environment. And it did!

Next step was to create a DomainService which got an IRepository injected in the constructor. This service is hosted in the ASP.NET MVC application. And it actually ... works:i can get data out of it to a Silverlight application.

Sample snippet:

public OrganizationDomainService(IRepository<Culture> cultureRepository)
{
            this.cultureRepository = cultureRepository;
}

Last step is to see if it works multi-tenant-like: it does not! The weird thing is this: using some line of code and writing debug messages in a log file i verified that the correct handler is selected! BUT this handler seems not to be injected in the DomainService. I ALWAYS get the first handler (that's the logic in my SelectHandler)

Can anybody verify this behavior? Is injection not working in RIA Services? Or am i missing something basic??

Development environment: Visual Studio 2010 Beta2

Th开发者_C百科anks in advance


So it seems i did a very weird thing in my OrganizationDomainServiceFactory. The code which did NOT work is this:

public DomainService CreateDomainService(Type domainServiceType, DomainServiceContext context  )
{
WindsorContainer container = new WindsorContainer(new XmlInterpreter(new ConfigResource("castle")));
IRepository<Culture> cultureRepository = container.Resolve<IRepository<Culture>>();
IRepository<Currency> currencyRepository = container.Resolve<IRepository<Currency>>();

DomainService ds = (DomainService)Activator.CreateInstance(domainServiceType, new object[] { cultureRepository,currencyRepository });

ds.Initialize(context);
return ds;
}

This is apparently not working, because of the creation of a new Container (which should not take place).

OK! So i thought i try to use ServiceLocator to get a reference to the Windsor Container (used in the WindsorControllerFactory - that's how i call it ... in the boot up of the ASP.NET MVC application), and changed the code to this:

public DomainService CreateDomainService(Type domainServiceType, DomainServiceContext context  )
{
IRepository<Culture> cultureRepository = ServiceLocator.Current.GetInstance<IRepository<Culture>>();
IRepository<Currency> currencyRepository = ServiceLocator.Current.GetInstance<IRepository<Currency>>();

DomainService ds = (DomainService)Activator.CreateInstance(domainServiceType, new object[] { cultureRepository,currencyRepository });

ds.Initialize(context);
return ds;
}

and guess what: it works(!!!) multi-tenancy as it should be!

The only thing i don't know is: is there another way to "inject" the container (constructor injection seems not to work here , the compiler complains)

BTW: moved the project from VS2010Beta2 to VS2010RC (with RIA Services support), but this should not affect the outcome!


Yes i have seen this thread and i already have implemented this. Firstly have in mind that i have used this line in Global.asax.cs to get the RIA services properly behave (hosted in an ASP.NET MVC view)

 routes.IgnoreRoute("{*allsvc}", new { allsvc = @".*\.svc(/.*)?" }); 

Here is some code:

public class HostBasedComponentSelector : IHandlerSelector
    {
        private readonly Type[] selectableTypes;

        public HostBasedComponentSelector(params Type[] selectableTypes)
        {
            this.selectableTypes = selectableTypes;
        }



        public bool HasOpinionAbout(string key, Type service)
        {
            foreach (var type in selectableTypes)
            {
                if (service == type) return true;
            }
            return false;
        }

        public IHandler SelectHandler(string key, Type service, IHandler[] handlers)
        {   
            //only for debug
            StreamWriter sw = new StreamWriter(@"c:\temp\Debug.log",true);
            sw.WriteLine(DateTime.Now + " " + service.Name + " " + GetHostname() );
            sw.WriteLine("Available handlers");
            foreach(IHandler h in  handlers )
            {
                sw.WriteLine ("Handler "+h.ComponentModel.Name);
            }

            var id = string.Format("{0}:{1}", service.Name, GetHostname());
            var selectedHandler = handlers.Where(h => h.ComponentModel.Name == id).FirstOrDefault() ??
                                  GetDefaultHandler(service, handlers);

            sw.WriteLine("Selected handler " + selectedHandler.ComponentModel.Name);
            sw.WriteLine("----------- END ----------");
            sw.Flush();
            sw.Close();


            return selectedHandler;
        }
        private IHandler GetDefaultHandler(Type service, IHandler[] handlers)
        {
            if (handlers.Length == 0)
            {
                throw new ApplicationException("No components registered for service {0} With service.Name" + service.Name);
            }
            return handlers[0];
        }

        protected string GetHostname()
        {
            return HttpContext.Current.Request.ServerVariables["SERVER_NAME"];
        }

    }

Here is the complete web.config. Notice registering the OrganizationDomainServiceFactory (it is the implementation of the article you mentioned)

<?xml version="1.0"?>
<!--
  For more information on how to configure your ASP.NET application, please visit
  http://go.microsoft.com/fwlink/?LinkId=152368
  -->
<configuration>
  <configSections>
    <section name="castle" type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler,Castle.Windsor"/>
  </configSections>
  <connectionStrings>
    <add name="ApplicationServices" connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true" providerName="System.Data.SqlClient"/>
  </connectionStrings>
  <castle>
    <properties>
      <sqlConnStr>
        <!--metadata=res://*/WebShop.csdl|res://*/WebShop.ssdl|res://*/WebShop.msl;provider=System.Data.SqlClient;provider connection string="Data Source=.\SQLEXPRESS;Initial Catalog=iWebShop;User ID=sa;Password=xxx;MultipleActiveResultSets=True"-->
      </sqlConnStr>
    </properties>
    <components>          
      <component id="CommonObjectContext" service="TestRIA1.Abstract.IObjectContext, TestRIA1" type="TestRIA1.Concrete.ObjectContextAdapter, TestRIA1" lifestyle="PerWebRequest">
      </component>

      <component id="IConnectionStringProvider:test.gammasys.gr" service="TestRIA1.Abstract.IConnectionStringProvider, TestRIA1" type="TestRIA1.Concrete.ConnectionStringProvider, TestRIA1" lifestyle="transient">
        <parameters>
          <ConnectionString>
            metadata=res://*/WebShop.csdl|res://*/WebShop.ssdl|res://*/WebShop.msl;provider=System.Data.SqlClient;provider connection string="Data Source=.\SQLEXPRESS;Initial Catalog=iWebShop;User ID=sa;Password=xxx;MultipleActiveResultSets=True"
          </ConnectionString>
        </parameters>
      </component>

      <component id="IConnectionStringProvider:test.deltasys.gr" service="TestRIA1.Abstract.IConnectionStringProvider, TestRIA1" type="TestRIA1.Concrete.ConnectionStringProvider, TestRIA1" lifestyle="transient">
        <parameters>
          <ConnectionString>
            metadata=res://*/WebShop.csdl|res://*/WebShop.ssdl|res://*/WebShop.msl;provider=System.Data.SqlClient;provider connection string="Data Source=.\SQLEXPRESS;Initial Catalog=iWebShop2;User ID=sa;Password=xxx;MultipleActiveResultSets=True"
          </ConnectionString>
        </parameters>
      </component>

      <component id="Commonrepository" service="TestRIA1.Abstract.IRepository`1, TestRIA1"   type="TestRIA1.Concrete.Repository`1, TestRIA1" lifestyle="PerWebRequest"/>

      <component id="urlbased.handlerselector" service="Castle.MicroKernel.IHandlerSelector, Castle.MicroKernel" type="TestRIA1.HostBasedComponentSelector, TestRIA1" lifestyle="transient">
        <parameters>
          <selectableTypes>
            <array>
              <item>TestRIA1.Abstract.IConnectionStringProvider, TestRIA1</item>
            </array>
          </selectableTypes>
        </parameters>
      </component>

    </components>
  </castle>
  <system.web>
    <compilation debug="true" targetFramework="4.0">
      <assemblies>
        <add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
        <add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
        <add assembly="System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
      </assemblies>
    </compilation>
    <authentication mode="Forms">
      <forms loginUrl="~/Account/LogOn" timeout="2880"/>
    </authentication>
    <membership>
      <providers>
        <clear/>
        <add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="ApplicationServices" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/"/>
      </providers>
    </membership>
    <profile>
      <providers>
        <clear/>
        <add name="AspNetSqlProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="ApplicationServices" applicationName="/"/>
      </providers>
    </profile>
    <roleManager enabled="false">
      <providers>
        <clear/>
        <add name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="ApplicationServices" applicationName="/"/>
        <add name="AspNetWindowsTokenRoleProvider" type="System.Web.Security.WindowsTokenRoleProvider" applicationName="/"/>
      </providers>
    </roleManager>
    <pages>
      <namespaces>
        <add namespace="System.Web.Mvc"/>
        <add namespace="System.Web.Mvc.Ajax"/>
        <add namespace="System.Web.Mvc.Html"/>
        <add namespace="System.Web.Routing"/>
      </namespaces>
    </pages>

    <httpHandlers>
      <add verb="*" path="*.mvc" validate="false" type="System.Web.Mvc.MvcHttpHandler"/>

    </httpHandlers>
    <httpModules>
      <add name="PerRequestLifestyle" type="Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule,Castle.MicroKernel " />
      <add name="DomainServiceModule" type="System.Web.Ria.Services.DomainServiceHttpModule, System.Web.Ria, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />

    </httpModules>
  </system.web>
  <system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
    <modules runAllManagedModulesForAllRequests="true">
      <add name="DomainServiceModule" preCondition="managedHandler"
       type="System.Web.Ria.Services.DomainServiceHttpModule, System.Web.Ria, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
      <remove name="PerRequestLifestyle"/>
      <add name="PerRequestLifestyle" preCondition="managedHandler" type="Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule,Castle.MicroKernel" />
      <!--to get IoC initialization of DomainService -->
      <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
      <add name="OrganizationDomainServiceFactory" type="TestRIA1.OrganizationDomainServiceFactory"/>
      <!-- End of IoC initial.....  -->

    </modules>
    <handlers>
      <remove name="MvcHttpHandler" />
      <add name="MvcHttpHandler" preCondition="integratedMode" verb="*"
       path="*.mvc" type="System.Web.Mvc.MvcHttpHandler" />
    </handlers>
  </system.webServer>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35"/>
        <bindingRedirect oldVersion="1.0.0.0" newVersion="2.0.0.0"/>
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
  <system.serviceModel>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
  </system.serviceModel>
</configuration>

Hope this is enough. In case you would like to have the complete project i can send you a copy (this is a pre-production test project).

Thank you very much for the time you spend!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜