0

[ServiceContract] 属性でマークされた (ウィンザー城の意味での) サービスがあります。それらの一部は WCF でホストされ、その他はローカルで実行されます。

インストーラーを可能な限り一般的なものにしたいと考えています。私が探しているロジックは次のとおりです。

  1. アプリケーションの bin ディレクトリでサービスを探します。
  2. 実装が見つかったものはすべて、ローカルで使用します (これはデコレータでも機能する必要があります)。
  3. 見つからないものはすべて、WCF 経由で呼び出されるものと想定します。

サービスは Web アプリケーションでホストされ、Application_Start メソッドはすべてをセットアップし、WCF を介してサービスをホストします。この Web アプリケーションでは、WCF を介した他のサービスへのアクセスも、追加のロジックなしで機能します。

ただし、ASP.NET MVC アプリケーションも持っていますが、WCF 経由でサービスを呼び出すことができません。私はいつも次のようなエラーメッセージが表示されます:

タイプ IMyService は抽象型です。そのため、サービス IMyService の実装としてインスタンス化することはできません。

そして、インターセプターを登録すると、

これは DynamicProxy2 エラーです: インターセプターは、ターゲットのないメソッド 'MyDataContract FooMethod(System.String)' に対して '続行' を試みました。ターゲットなしでメソッドを呼び出す場合、「続行」する実装はなく、実装を模倣するのはインターセプターの責任です (戻り値の設定、引数の出力など)。

これが私の最新の試みです(つまり、機能しないのは「ConfigureAsWcfClient」の部分です):

    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(
            Classes.FromAssemblyInDirectory(Constants.MyAssemblyFilter)
                   .Where(ImplementsServiceContract)
                   .WithServiceSelect((x, y) => GetServices(x))

#if DECORATORS_PRESENT
                   .ConfigureIf(IsDecorator, c => c
                       .IsDefault(y => IsDecorating(c, y))
                       .Named(GetNameOfServiceContract(c)))
#else
            // TODO: FIXME: Set name for services without decorator
                   .ConfigureIf(c => string.IsNullOrEmpty(c.Name),
                                c => c.Named(GetNameOfServiceContract(c)))
#endif
            );

        container.Register(Types.FromAssemblyInDirectory(Constants.BikubeAssemblyFilter)
                .Where(x => IsServiceContract(x) && !container.Kernel.HasComponent(x))
                .WithServiceSelf()
                .Configure(ConfigureAsWcfClient));
    }

    private static void ConfigureAsWcfClient(ComponentRegistration c)
    {
        c.Named(c.Implementation.Name).AsWcfClient(WcfEndpoint.FromConfiguration("*"));
    }

    private static string GetNameOfServiceContract(ComponentRegistration c)
    {
        var name = GetServices(c.Implementation).First().FullName;
        Debug.WriteLine("CW register sevice contract: " + name);
        return name;
    }

    private static bool ImplementsServiceContract(Type type)
    {
        return GetServices(type).Any();
    }

    private static IEnumerable<Type> GetServices(Type type)
    {
        return type.GetInterfaces().Where(IsServiceContract);
    }

    private static bool IsServiceContract(Type type)
    {
        var ns = type.Namespace;
        return ns != null && ns.StartsWith(Constants.NamespacePrefix) && Attribute.IsDefined(type, typeof(ServiceContractAttribute));
    }

    private static bool IsDecorator(ComponentRegistration c)
    {
        Type component = c.Implementation;
        var isDecorator = GetServices(component).Any(x => IsDecorating(c, x));
        return isDecorator;
    }

    private static bool IsDecorating(ComponentRegistration c, Type service)
    {
        Type component = c.Implementation;
        return !component.Assembly.GetName().Name.EndsWith(".Impl", StringComparison.InvariantCultureIgnoreCase);
    }

もちろん、プリプロセッサ ディレクティブも削除したいと思います。システムは、デコレータが存在するかどうかを自動的に検出する必要があります。「ローカル」実装は.Impl.dll という名前のアセンブリにあり、デコレータは * .ServiceProxy.*.dll という名前のアセンブリにあります。

ああ、ローカル以外のサービス (WCF 経由で呼び出されるサービス) の特別な処理を削除すると、常に「クライアント モデルにはエンドポイントが必要です」というエラー メッセージが表示されます。

どんな助けでも大歓迎です。

4

0 に答える 0