1

単一の再利用可能なクラスにカプセル化したい.NETサービスリファレンスがあります。

私の典型的な呼び出しは次のようになります。

// instantiate the api and set credentials
ApiClient api = new ApiClient();
api.Credentials.UserName.UserName = "blah";
api.Credentials.UserName.Password = "blahblah";

// operation-specific search parameter object
SomethingSearch search = new SomethingSearch();
search.Key = "blah";

Result[] result = api.GetSomething(search);

api.Close();

他の呼び出しは、呼び出される操作と検索パラメーターオブジェクトの両方で異なります。

GetSomething()問題は、API操作の名前(つまり、操作固有の検索オブジェクト( )の両方をクラスに渡す方法がわからないということですSomethingSearch

どうすればこれを達成できますか?私は自分のために仕事をするように求めているのではありませんが、どこから始めればよいのかわかりません。私はそれが彼らと関係があると信じています、Func<T>そして私は彼らと恥ずかしいほど経験がありません。

4

2 に答える 2

3

私の同僚がこのソリューションを開発しました。

/// <summary>
/// Proxy for executing generic service methods
/// </summary>
public class ServiceProxy
{
    /// <summary>
    /// Execute service method and get return value
    /// </summary>
    /// <typeparam name="C">Type of service</typeparam>
    /// <typeparam name="T">Type of return value</typeparam>
    /// <param name="action">Delegate for implementing the service method</param>
    /// <returns>Object of type T</returns>
    public static T Execute<C, T>(Func<C, T> action) where C : class, ICommunicationObject, new()
    {
        C svc = null;

        T result = default(T);

        try
        {
            svc = new C();

            result = action.Invoke(svc);

            svc.Close();
        }
        catch (FaultException ex)
        {
            // Logging goes here
            // Service Name: svc.GetType().Name
            // Method Name: action.Method.Name
            // Duration: You could note the time before/after the service call and calculate the difference
            // Exception: ex.Reason.ToString()

            if (svc != null)
            {
                svc.Abort();
            }

            throw;
        }
        catch (Exception ex)
        {
            // Logging goes here

            if (svc != null)
            {
                svc.Abort();
            }

            throw;
        }

        return result;
    }
}

そしてその使用例:

public class SecurityServiceProxy
{

    public static UserInformation GetUserInformation(Guid userId)
    {
        var result = ServiceProxy.Execute<MySecurityService, UserInformation>
        (
            svc => svc.GetUserInformation(userId)
        );

        return result;
    }

    public static bool IsUserAuthorized(UserCredentials creds, ActionInformation actionInfo)
    {
        var result = ServiceProxy.Execute<MySecurityService, bool>
        (
            svc => svc.IsUserAuthorized(creds, actionInfo)
        );

        return result;
    }
 }

この偽のケースでは、、、およびの2つのメソッドを使用してMySecurityServiceGetUserInformationますIsUserAuthorizedGetUserInformation引数としてaを取り、オブジェクトGuidを返しUserInformationます。 andオブジェクトIsUserAuthorizedを受け取り、ユーザーが許可されているかどうかを返します。UserCredentialsActionInformationbool

このプロキシは、キャッシュ可能なサービス呼び出しの結果をキャッシュするのにも最適な場所です。

サーバーにパラメーターを送信する必要がある場合は、より一般的な方法があるかもしれませんが、そのための特定のプロキシを作成する必要があると思います。例:

public interface ISecuredService
{
   public UserCredentials Credentials { get; set; }
}

/// <summary>
/// Proxy for executing generic UserCredentials  secured service methods
/// </summary>
public class SecuredServiceProxy
{
    /// <summary>
    /// Execute service method and get return value
    /// </summary>
    /// <typeparam name="C">Type of service</typeparam>
    /// <typeparam name="T">Type of return value</typeparam>
    /// <param name="credentials">Service credentials</param>
    /// <param name="action">Delegate for implementing the service method</param>
    /// <returns>Object of type T</returns>
    public static T Execute<C, T>(UserCredentials credentials, Func<C, T> action) where C : class, ICommunicationObject, ISecuredService, new()
    {
        C svc = null;

        T result = default(T);

        try
        {
            svc = new C();
            svc.Credentials = credentials;

            result = action.Invoke(svc);

            svc.Close();
        }
        catch (FaultException ex)
        {
            // Logging goes here
            // Service Name: svc.GetType().Name
            // Method Name: action.Method.Name
            // Duration: You could note the time before/after the service call and calculate the difference
            // Exception: ex.Reason.ToString()

            if (svc != null)
            {
                svc.Abort();
            }

            throw;
        }
        catch (Exception ex)
        {
            // Logging goes here

            if (svc != null)
            {
                svc.Abort();
            }

            throw;
        }

        return result;
    }
}
于 2012-07-10T22:28:52.557 に答える
1

ほとんどのWCF実装に同様のアプローチを取り、API機能を定義し、そのインターフェイスの背後に実装を隠すインターフェイスを作成できます。コードサンプルを使用した簡単な例を次に示します。

    class APIEngine :IApiProvider
    {
        //...Private stuff & other methods
        T[] Search<T>(SearchArgs args)
        {
           //Error handling ommitted
           T[] result;

           switch(args.SearchType)
           {
               case(SearchType.GetSomething)
                    result = GetSomethingSearch(args.Key);
                    break;
               // and so on
           }     


           api.Close();
          return result;
       }
       Result[] GetSomethingSearch(Key searchKey)
       {   
           ApiClient api = new ApiClient(); 
           api.Credentials.UserName.UserName = "blah";
           api.Credentials.UserName.Password = "blahblah";   

           object SomethingSearch search = new SomethingSearch(); 
           search.Key = searchKey;

           result = api.GetSomething(search);  
       }
    }


class SearchArgs
{
    SearchType SearchType {get; set;} //Enum of search types
    SearchKey Key {get; set;} //SearchKey would be parent class for different key types
{

これは、他のインターフェイスと同じように呼び出すことができます。

IApiProvider.Search(keyValue);

他のすべては、建設中に設定することも、専用の方法で後で再設定することもできます。これが実際にあなたの質問に答えない場合は私に知らせてください。

編集:

引数にラッパークラスを使用すると、大文字と小文字を区別してSearchTypeに基づいて正しいタイプを判別することにより、任意の数のSearchタイプを取得できる単一の使いやすいSearchメソッドを使用できます。

于 2012-07-10T21:40:34.977 に答える