4

私の目標は、複数のアセンブリを解析し、コントラクトを検出し、サービスをホストできるホスト アプリケーションを作成することです。

サービスをロードするには、通常、サービスホストのインスタンス化をハードコーディングする必要があります。次のコードは、私が探している動作ではありませんが、機能しています。

ServiceHost wService1Host = new ServiceHost(typeof(Service1));
wService1Host.Open();

ServiceHost wService2Host = new ServiceHost(typeof(Service2));
wService2Host.Open();

ただし、これは、サービスがどうなるかを事前に知っていることを意味します。サービスを含むアセンブリへの参照があってもかまいません。アセンブリに含まれるサービスをホストに知られたくないだけです。たとえば、アセンブリの 1 つに新しいサービスを追加した場合、ホスト側で変更は必要ありません。

これはこの質問と非常によく似ていますが、上記の理由により複雑さが増しています。

ここに私がこれまでに持ってきたホストコードがあります。現時点では、サービスを管理することは気にしません。単に適切にロードされることを望んでいます。

class Program
  {
    static void Main(string[] args)
    {

      // find currently executing assembly
      Assembly curr = Assembly.GetExecutingAssembly();

      // get the directory where this app is running in
      string currentLocation = Path.GetDirectoryName(curr.Location);

      // find all assemblies inside that directory
      string[] assemblies = Directory.GetFiles(currentLocation, "*.dll");

      // enumerate over those assemblies
      foreach (string assemblyName in assemblies)
      {
        // load assembly just for inspection
        Assembly assemblyToInspect = Assembly.ReflectionOnlyLoadFrom(assemblyName);

        // I've hardcoded the name of the assembly containing the services only to ease debugging
        if (assemblyToInspect != null && assemblyToInspect.GetName().Name == "WcfServices")
        {
          // find all types
          Type[] types = assemblyToInspect.GetTypes();

          // enumerate types and determine if this assembly contains any types of interest
          // you could e.g. put a "marker" interface on those (service implementation)
          // types of interest, or you could use a specific naming convention (all types
          // like "SomeThingOrAnotherService" - ending in "Service" - are your services)
          // or some kind of a lookup table (e.g. the list of types you need to find from
          // parsing the app.config file)
          foreach (Type ty in types)
          {
            Assembly implementationAssembly = Assembly.GetAssembly(ty);
            // When loading the type for the service, load it from the implementing assembly.
            Type implementation = implementationAssembly.GetType(ty.FullName);

            ServiceHost wServiceHost = new ServiceHost(implementation); // FAIL
            wServiceHost.Open();
          }
        }
      }
      Console.WriteLine("Service are up and running.");
      Console.WriteLine("Press <Enter> to stop services...");
      Console.ReadLine();
    }
  }

serviceHost を作成しようとすると、次のエラーが発生します。

"It is illegal to reflect on the custom attributes of a Type loaded via ReflectionOnlyGetType (see Assembly.ReflectionOnly) -- use CustomAttributeData instead."

上記のリンクでは、公開したいサービスを事前に知っているため、その人は typeof を使用して問題を解決したようです。残念ながら、これは私の場合ではありません。

注:ホスティング部分については、実際には3つのプロジェクトがあります。1 つ目はホスト アプリケーション (上記を参照) で、2 つ目はすべてのサービスのコントラクト (インターフェイス) を含むアセンブリで、最後のアセンブリにはサービスの実装が含まれます。

サービスのホスティングに実際に使用する app.config を次に示します。実装を含むアセンブリは "WcfServices" という名前で、2 つのサービスが含まれています。1 つはコールバックを公開することで、もう 1 つは基本的なサービスのみを公開することです。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>    
    <behaviors>
      <serviceBehaviors>  
        <behavior name="metadataBehavior">
          <serviceMetadata httpGetEnabled="true"/>
        </behavior>        
      </serviceBehaviors>  
    </behaviors>
    <services>
      <service name="WcfServices.Service1"
               behaviorConfiguration="metadataBehavior">

        <endpoint address="Service1Service"
                  binding="basicHttpBinding"
                  contract="WcfServices.IService1"
                  name="basicHttp"/>

        <endpoint binding="mexHttpBinding"
                  contract="IMetadataExchange"
                  name="metadataExchange"/>

        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8000/Service1"/>
          </baseAddresses>
        </host>        
      </service>

      <service name="WcfServices.Service2"
               behaviorConfiguration="metadataBehavior">

        <endpoint address="Service2Service"
                  binding="wsDualHttpBinding"
                  contract="WcfServices.IService2"/>

        <endpoint address="mex"
                  binding="mexHttpBinding"
                  contract="IMetadataExchange"/>

        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8000/Service2"/>
          </baseAddresses>
        </host>
      </service>

    </services>    
  </system.serviceModel>
</configuration>

明確にするために、ここに私が探しているものがあります:
1.現在のアプリディレクトリにアセンブリをロードします
2.そこにコントラクトの実装があるかどうかを調べ
ます3.ある場合は、それらのサービスをインスタンス化します(今のところapp.configを使用) )

まず第一に、これは可能ですか?(私の推測では、wcfstorm という名前のアプリケーションが既にこれを行っているようです)
明らかに、上記のコードを機能させるにはどうすればよいでしょうか?

ありがとうございました!

4

1 に答える 1

4

これが私がやったことです:

private static void LoadServices()
{
  // find currently executing assembly
  Assembly Wcurr = Assembly.GetExecutingAssembly();

  // get the directory where this app is running in
  string wCurrentLocation = Path.GetDirectoryName(Wcurr.Location);

  // enumerate over those assemblies
  foreach (string wAssemblyName in mAssemblies)
  {
    // load assembly just for inspection
    Assembly wAssemblyToInspect = null;
    try
    {
      wAssemblyToInspect = Assembly.LoadFrom(wCurrentLocation + "\\" + wAssemblyName);
    }
    catch (System.Exception ex)
    {
      Console.WriteLine("Unable to load assembly : {0}", wAssemblyName);
    }


    if (wAssemblyToInspect != null)
    {
      // find all types with the HostService attribute
      IEnumerable<Type> wTypes = wAssemblyToInspect.GetTypes().Where(t => Attribute.IsDefined(t, typeof(HostService), false));

      foreach (Type wType in wTypes)
      {
        ServiceHost wServiceHost = new ServiceHost(wType);
        wServiceHost.Open();
        mServices.Add(wServiceHost);
        Console.WriteLine("New Service Hosted : {0}", wType.Name);
      }
    }
  }

  Console.WriteLine("Services are up and running.");
}

注 : このアプローチでは、アセンブリが「ホスト」プロジェクトによって参照される必要があります。

注 2 : アセンブリの解析を高速化するために、どのアセンブリを "mAssemblies" に読み込むかをハードコーディングしました。

于 2012-10-24T19:16:30.033 に答える