【问题标题】:Windsor IHandlerSelector in RIA Services Visual Studio 2010 Beta2RIA Services Visual Studio 2010 Beta2 中的 Windsor IHandlerSelector
【发布时间】:2010-03-15 19:58:40
【问题描述】:

我想使用 Windsor 实现多租户,但我不知道如何处理这种情况:

我在普通的 ASP.NET MVC 项目中成功使用了this 技术,并认为将其合并到 RIA 服务项目中会是类似的。

所以我使用了 IHandlerSelector,注册了一些组件并编写了一个 ASP.NET MVC 视图来验证它是否可以在普通的 ASP.NET MVC 环境中工作。确实如此!

下一步是创建一个 DomainService,它在构造函数中注入了一个 IRepository。此服务托管在 ASP.NET MVC 应用程序中。它实际上...有效:我可以从中获取数据到 Silverlight 应用程序。

示例 sn-p:

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

最后一步是看看它是否可以像多租户一样工作:它不能!奇怪的是: 使用某行代码并在日志文件中编写调试消息,我验证选择了正确的处理程序!但是这个处理程序似乎没有注入到 DomainService 中。我总是得到第一个处理程序(这是我的 SelectHandler 中的逻辑)

任何人都可以验证这种行为吗?注入在 RIA 服务中不起作用吗?还是我缺少一些基本的东西??

开发环境:Visual Studio 2010 Beta2

提前致谢

【问题讨论】:

标签: castle-windsor ioc-container wcf-ria-services


【解决方案1】:

看来我在我的 OrganizationDomainServiceFactory 中做了一件非常奇怪的事情。 不起作用的代码是这样的:

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;
}

这显然是行不通的,因为创建了一个新容器(不应该发生)。

好的!所以我想我尝试使用 ServiceLocator 来获取对 Windsor Container 的引用(在 WindsorControllerFactory 中使用 - 这就是我在启动 ASP.NET MVC 应用程序时调用它的方式),并将代码更改为:

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;
}

你猜怎么着:它可以工作(!!!)它应该是多租户!

我唯一不知道的是:是否有另一种“注入”容器的方法(构造函数注入在这里似乎不起作用,编译器抱怨)

顺便说一句:将项目从 VS2010Beta2 移至 VS2010RC(支持 RIA 服务),但这不会影响结果!

【讨论】:

    【解决方案2】:

    是的,我已经看到了这个线程并且我已经实现了这个。 首先请记住,我在 Global.asax.cs 中使用了这一行来使 RIA 服务正常运行(托管在 ASP.NET MVC 视图中)

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

    这里有一些代码:

    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"];
            }
    
        }
    

    这是完整的 web.config。注意注册OrganizationDomainServiceFactory(就是你说的那篇文章的实现)

    <?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>
    

    希望这已经足够了。如果您想要完整的项目,我可以向您发送一份副本(这是一个预生产测试项目)。

    非常感谢您花费的时间!

    【讨论】:

    • OrganizationDomainServiceFactory 是如何知道温莎的?您使用的是静态 IoC 网关吗?这篇文章做了一个Activator.CreateInstance&lt;TServiceLocator&gt;(),这看起来不太对。
    猜你喜欢
    • 2011-08-29
    • 2018-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多