SharePoint2010 Custom Service

Create Custom Service Class

Service类用来定义这个自定义“Service”,也是各种功能的入口点。它继承SPIisWebService,并实现IServiceAdministration(以接入到管理系统中)。

[Guid("E828358E-E24C-4D78-BE87-C69D458766F4")]

public class KaneboyService : SPIisWebService, IServiceAdministration

Service类通常实现二个构造函数:

  • 默认构造函数
  • 一个参数为SPFarm对象的构造函数

public KaneboyService() { }

 

public KaneboyService(SPFarm farm) : base(farm) { }

IServiceAdministration的方法:

  • CreateApplication():创建一个SPServiceApplication对象。只有在通过运行psconfig.exe或farm configuration wizard创建Service Application时才会调用它(所以对于自定义SPService,它通常不会有机会被调用)。
  • CreateProxy():创建一个SPServiceApplicationProxy对象。与CreateApplication()类似。
  • GetApplicationTypeDescription():返回对此Service的描述信息。
  • GetApplicationTypes():返回Service Application的类型。
  • GetCreateApplicationLink():如果希望可以在管理中心的“管理服务应用程序”中新建此Service Application实例,那么需要实现此方法并返回新建Service Application页面的URL。

Create Custom Service Instance Class

Service Instance用来描述运行在每个SPServer上的Service实例。它继承SPIisWebServiceInstance。

public class KaneboyServiceInstance : SPIisWebServiceInstance

Service Instance类的构造函数:

  • 默认构造函数
  • 参数如下的构造函数:
    • 一个SPServer对象,表示运行此Service实例的Server
    • 所对应的SPIisWebService对象

public KaneboyServiceInstance() : base() { }

 

public KaneboyServiceInstance(SPServer server, SPIisWebService service) : base(server, service) { }

Service Instance类需要实现的方法:

  • TypeName属性:描述此Service Instance的名称,显示在管理UI。

Create Custom Service Application Class

Service Application类是对Service Application的实现。它继承SPIisWebServiceApplication,并通常实现Service Contract接口。

[IisWebServiceApplicationBackupBehavior]

[ServiceBehavior(

        InstanceContextMode = InstanceContextMode.PerSession,

        ConcurrencyMode = ConcurrencyMode.Multiple,

        IncludeExceptionDetailInFaults = true)]

[Guid("933A11F0-7265-4694-97C0-FE04BFB370A5")]

public class KaneboyServiceApplication : SPIisWebServiceApplication, IKaneboyServiceContract

Service Application类的构造函数:

  • 默认构造函数
  • 带下列参数的构造函数:
    • Service Application名称
    • 所对应的SPIisWebService对象
    • 所使用的SPIisWebServiceApplicationPool对象

public KaneboyServiceApplication() : base() { }

 

private KaneboyServiceApplication(String name, KaneboyService service, SPIisWebServiceApplicationPool appPool) : base(name, service, appPool) { }

Service Application需要告诉系统,如何连接到WCF Service,所以它需要实现:

  • InstallPath属性:返回.svc所在的目录。
  • VirtualPath属性:返回.svc文件的名称。

如果在Provision这个Service Application的时候,还需要Provision数据库或其他资源,可以重载Provision()和Unprovision()方法。

创建(并Provision)一个Service Application不能直接使用它的构造函数,而是需要使用如下步骤:

  • 创建Service Application至少需要用到如下信息:
    • Service Application名称
    • 它所对应的SPService对象
    • 它所使用的SPIisWebServiceApplicationPool对象
    • 通过SPService.Applications.GetValue(),确定这个Service Application是否有其他实例存在。
    • 使用它的构造函数,新建一个实例对象。
    • 调用SPServiceApplication.Update()保存新建的实例。
    • 调用SPServiceApplication.AddServiceEndpoint()为Service Application新建WCF Endpoint。

serviceApp.AddServiceEndpoint("http", SPIisWebServiceBindingType.Http);

serviceApp.AddServiceEndpoint("https", SPIisWebServiceBindingType.Https, "secure");

  • 调用SPServiceApplication.Provision()以Provision它。

创建并Provision 自定义Service Application的方法,可以放到Service Application类中,以static method提供。管理员可以使用管理中心UI(位于”ADMIN”中的自定义.aspx,路径由IServiceAdministration.GetCreateApplicationLink()指定)或自定义powershell cmdlets来完成这个操作,所以在管理中心UI或自定义cmdlets中,需要调用这个static method。

WCF Artifacts

首先,需要一个自定义Host Factory类,继承自ServiceHostFactory。

public class KaneboyServiceHostFactory : ServiceHostFactory

它重载CreateServiceHost()方法,创建并返回一个ServiceHost对象。

public override ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses)

{

ServiceHost serviceHost = new ServiceHost(typeof(KaneboyServiceApplication), baseAddresses);

serviceHost.Configure(SPServiceAuthenticationMode.Claims);

return serviceHost;

}

在”WebServices”这个mapped folder下面,需要放置自定义Service Application的.svc文件和定义WCF channel的web.config。.svc只需要通过标签告知Service和Factory类即可。

<%@ServiceHost Language="C#" Debug="true"

               Service="KaneboyServiceApp1.KaneboyServiceApplication, $SharePoint.Project.AssemblyFullName$"

               Factory="KaneboyServiceApp1.KaneboyServiceHostFactory, $SharePoint.Project.AssemblyFullName$" %>

web.config里面需要定义Service Application将使用的channel。

<configuration>

  <system.serviceModel>

    <services>

      <service name="KaneboyServiceApp1.KaneboyServiceApplication">

        <endpoint

          address=""

          contract="KaneboyServiceApp1.IKaneboyServiceContract"

          binding="customBinding"

          bindingConfiguration="CustomServiceHttpBinding" />

        <endpoint

          address="secure"

          contract="KaneboyServiceApp1.IKaneboyServiceContract"

          binding="customBinding"

          bindingConfiguration="CustomServiceHttpsBinding" />

       </service>

    </services>

    <bindings>

      <customBinding>

        …

      </customBinding>

    </bindings>

  </system.serviceModel>

  <system.webServer>

    <security>

      …

    </security>

  </system.webServer>

</configuration>

Register Service on Farm

将Service注册到Farm里面,需要创建Service和Service Instance对象,并将它们Persist到Config DB中(通过调用Update())。注册可以通过一个Farm Feature的activate事件来实现。在新建Service和Service Instance对象之前,可以通过调用SPFarm.Services.GetValue()来确认是否Farm中已经注册了此服务。在Farm Feature的deactivate事件中,可以将相关的Service和Service Instance删除。

Create and Provision Service Application

新建Service Application的实例,可以使用管理中心UI(“管理服务应用程序”)或自定义powershell cmdlets来实现。如果是通过管理中心UI,可以在“ADMIN”中新建一个.aspx,并将其路径在Service类中通过IServiceAdministration.GetCreateApplicationLink()告知系统。

无论哪种方法,最关键的是,如何将Service Application所使用的SPIisWebServiceApplicationPool对象传递给新建Service Application的代码。如果是使用.aspx,可以使用” ~/_admin/IisWebServiceApplicationPoolSection.ascx”控件,然后通过IisWebServiceApplicationPoolSection.GetOrCreateApplicationPool()得到用户选择的App Pool。如果是使用cmdlets,那么就通过SPIisWebServiceApplicationPoolPipeBind类来得到App Pool信息。(Check MSDN to get detail information.)

------------------ “Server”(App Server)与”Client”(WFE)的分割线 ----------------------

WCF Artifacts

在”WebClients”这个mapped folder下面,将一个”client.config”文件放置到一个自定义目录中,此文件中包含了告知Service Application Proxy通过哪个channel连接到Service Application的配置信息。

<configuration>

  <system.serviceModel>

    <client>

      <endpoint

        name="http"

        contract="KaneboyServiceApp1.IKaneboyServiceContract"

        binding="customBinding"

        bindingConfiguration="CustomServiceHttpBinding" />

      <endpoint

        name="https"

        contract="KaneboyServiceApp1.IKaneboyServiceContract"

        binding="customBinding"

        bindingConfiguration="CustomServiceHttpsBinding" />

    </client>

    <bindings>

      <customBinding>

            …

      </customBinding>

    </bindings>

  </system.serviceModel>

</configuration>

 

Create Custom Service Proxy Class

Service Proxy类用来描述service consumer。它继承SPIisWebServiceProxy,并实现IServiceProxyAdministration。

[SupportedServiceApplication("933A11F0-7265-4694-97C0-FE04BFB370A5", "1.0.0.0", typeof(KaneboyServiceApplicationProxy))]

[Guid("44203351-1E42-413E-BAAA-42A4A0788A8D")]

public class KaneboyServiceProxy : SPIisWebServiceProxy, IServiceProxyAdministration

Service Proxy类的构造函数:

  • 默认构造函数
  • 参数为SPFarm对象的构造函数

IServiceProxyAdministration的方法:

  • CreateProxy():创建一个SPServiceApplicationProxy。
  • GetProxyTypeDescription():返回对此Service Proxy的描述。
  • GetProxyTypes():返回Service Application Proxy的类型。

Create Custom Service Application Proxy Class

Service Application Proxy类定义了连接到Service Application的接口,Service Consumer通过它实现对Service的调用。它继承SPIisWebServiceApplicationProxy类。

[IisWebServiceApplicationProxyBackupBehavior]

[System.Runtime.InteropServices.Guid("6339C282-E7D3-4B0D-94DF-2D09773FDF80")]

public class KaneboyServiceApplicationProxy : SPIisWebServiceApplicationProxy

Service Application Proxy类的构造函数:

  • 默认构造函数
  • 包含以下参数的构造函数:
    • Service Application Proxy的名称
    • 所对应的Service Proxy对象
    • Service Application的Endpoint URL

public KaneboyServiceApplicationProxy() : base() {}

 

public KaneboyServiceApplicationProxy(String name, KaneboyServiceProxy serviceProxy, Uri serviceEndpointUri) : base(name, serviceProxy, serviceEndpointUri)

{

_loadBalancer = new SPRoundRobinServiceLoadBalancer(serviceEndpointUri);

}

由于Service Application通常需要Load Balance的能力,所以Service Application Proxy通常会包含一个SPServiceLoadBalancer类型field,它可以使用SharePoint内置提供的SPRoundRobinServiceLoadBalancer类来实例化。SPRoundRobinServiceLoadBalancer类需要给出Service Application的URL来进行构造。

Service Application Proxy要实现的方法:

  • 一个根据Service Application的Url,获取Endpoint Configuration名称(对应到client.config中”<Endpoint>”节点的”name”属性)的方法(如“GetEndpointConfigurationName()”),Endpoint Configuration的名称通常是“http”和“https”。
  • 一个创建并返回ChannelFactory<T>的方法(如“CreateChannelFactory()”),它需要读取client.config中的信息。

private ChannelFactory<T> CreateChannelFactory<T>(string endpointConfigName)

{

// open client.config

string clientConfigPath = SPUtility.GetGenericSetupPath(@"WebClients\KaneboyServiceApp1");

Configuration clientConfig = OpenClientConfiguration(clientConfigPath);

ConfigurationChannelFactory<T> factory = new ConfigurationChannelFactory<T>(endpointConfigName, clientConfig, null);

 

// configure the channel factory for IDFx claims auth

factory.ConfigureCredentials(SPServiceAuthenticationMode.Claims);

 

return factory;

}

  • 一个获取Channel(Service Contract接口)的方法,通过调用ChannelFactory. CreateChannelActingAsLoggedOnUser<T>(),来获取Channel。

private IKaneboyServiceContract GetChannel(Uri address)

{

    // get the endpoint config name

    string endpointConfigName = GetEndpointConfigurationName(address);

 

    ChannelFactory<IKaneboyServiceContract> channelFactory = CreateChannelFactory<IKaneboyServiceContract>(endpointConfigName);

 

    IKaneboyServiceContract channel  = channelFactory.CreateChannelActingAsLoggedOnUser<IKaneboyServiceContract>(new EndpointAddress(address));

    return channel;

}

结合以上的Helper方法,就可以拿到可以透过WCF远程调用Service Application的Channel对象。

创建(并Provision)一个Service Application Proxy的步骤如下:

  • 调用Service Application Proxy构造函数,新建实例。
  • 调用SPServiceApplicationProxy.Update(true)将对象persist到ConfigDB中。
  • 调用SPServiceApplicationProxy.Provision()。

类似Service Application,创建Service Application Proxy的方法可以放到此类中,以static method的方式提供。

Create and Provision Service Application Proxy

新建并Provision Service Application Proxy,类似Service Application,可以使用管理中心UI或自定义powershell cmelets实现。

如果是使用管理中心UI,可以在创建并Provision了Service Application之后,紧接着创建Service Application Proxy。如果是创建cmdlets,可以使用SPServiceApplicationPipeBind来得到其所对应的Service Application。

Invoke Service

通过Service Application Proxy调用Service Application所提供的功能,步骤如下:

  • 获取SPServiceApplicationProxy对象,可以通过SPServiceContext.GetDefaultProxy()来获得。
  • 调用SPServiceApplicationProxy对象所持有的SPServiceLoadBalancer对象的BeginOperation()获取一个SPServiceLoadBalancerContext对象,然后通过使用SPServiceLoadBalancerContext.EndpointAddress拿到这次请求需要调用的Endpoint Url。使用此Url,并通过调用Service Application Proxy中的Helper方法,拿到IChannel对象,也就是实现了Service Contract的对象。
  • 调用IChannel上的方法
  • 使用IChannel.Close()关闭连接。
  • 调用SPServiceLoadBalancer.EndOperation()告知完成了Load Balance操作。
posted @ 2013-07-04 17:02  休天  阅读(291)  评论(0编辑  收藏  举报