Виндзор IHandlerSelector в RIA Services Visual Studio 2010 Beta2 - PullRequest
1 голос
/ 15 марта 2010

Я хочу реализовать многопользовательский режим с использованием Windsor, и я не знаю, как справиться с этой ситуацией:

я успешно использовал этот метод в простых проектах ASP.NET MVC и думал, что включение в проект RIA Services будет аналогичным.

Поэтому я использовал IHandlerSelector, зарегистрировал некоторые компоненты и написал представление ASP.NET MVC, чтобы убедиться, что оно работает в простой среде ASP.NET MVC. И это сделал!

Следующим шагом было создание службы DomainService, в которую был добавлен IRepository в конструктор. Этот сервис размещен в приложении ASP.NET MVC. И это на самом деле ... работает: я могу получить данные из него в приложение Silverlight.

Пример фрагмента:

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

Последний шаг - посмотреть, работает ли он как мультитенант: не работает! Странная вещь заключается в следующем: используя некоторую строку кода и записывая отладочные сообщения в файл журнала, я убедился, что выбран правильный обработчик! НО этот обработчик, похоже, не внедряется в DomainService. Я ВСЕГДА получаю первый обработчик (это логика в моем SelectHandler)

Кто-нибудь может проверить это поведение? Инъекция не работает в RIA Services? Или я упускаю что-то простое ??

Среда разработки: Visual Studio 2010 Beta2

Заранее спасибо

Ответы [ 2 ]

1 голос
/ 17 марта 2010

Так что, похоже, я сделал очень странную вещь в своей организации 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;
}

Это, очевидно, не работает из-за создания нового контейнера (который не должен иметь место).

OK! Поэтому я решил использовать 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 Services), но это не должно повлиять на результат!

0 голосов
/ 16 марта 2010

Да, я видел эту тему, и я уже реализовал это. Во-первых, имейте в виду, что я использовал эту строку в 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>

Надеюсь, этого достаточно. Если вы хотите получить полный проект, я могу выслать вам копию (это предварительный тестовый проект).

Большое спасибо за потраченное время!

...