我有一个.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();
其他调用在被调用的操作和搜索参数对象中都有所不同。
问题是,我不知道如何将API操作的名称(即GetSomething()
和特定于操作的搜索对象(SomethingSearch
)传递给类。
我怎么能做到这一点?我不是要求为我做的工作,但我不知道从哪里开始。我认为它与Func<T>
和代表有关,但我对它们缺乏经验。
答案 0 :(得分: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;
}
}
在这个假例中,我们使用了MySecurityService
,GetUserInformation
和IsUserAuthorized
中的两种方法。 GetUserInformation
将Guid
作为参数并返回UserInformation
个对象。 IsUserAuthorized
获取UserCredentials
和ActionInformation
个对象,无论用户是否获得授权,都会返回bool
。
此代理也是缓存可缓存服务调用结果的理想之地。
如果您需要向服务器发送参数,可能有更通用的方法,但我认为您需要为它创建一个特定的代理。例如:
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;
}
}
答案 1 :(得分:1)
您可以采用类似于大多数WCF实现的方法。创建一个定义API功能的接口&amp;隐藏该接口背后的实现。以下是使用代码示例的简单示例:
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确定正确的类型。