注释
这很可能是
C#
特定语言问题,与
WCF
或
web services
完全。
有三个派对
ASMX
Web服务,用于数据检索。我创建了一个名为
ExecuteCommand()
它用于针对Web服务的每个请求。此方法的目的是处理cookie会话/异常和其他常见逻辑。对于每个请求,应使用新的通道,以简化未使用资源的处理。
问题是使用
执行命令()
方法-我必须每次初始化一个通道,以便能够传递要作为参数执行的方法。如果这听起来太复杂,对不起。下面是一个用法示例:
string color = "blue";
var channel = _strategyFactory.CreateChannel<CarServiceSoapChannel>();
var cars = WcfHelper.ExecuteCommand(channel, () => channel.GetCars(color));
// channel is null here. Channel was closed/aborted, depending on Exception type.
后
执行命令()
被调用-
channel
已释放。为什么
通道
对象是完全需要的,是能够提供一个方法来作为参数执行的!即
() => channel.GetCars()
。为了进一步支持这些话,这里是
WcfHelper
类内部构件:
public static class WcfHelper
{
public static Cookie Cookie { get; set; }
public static T ExecuteCommand<T>(IClientChannel channel, Expression<Func<T>> method)
{
T result = default(T);
try
{
// init operation context
using (new OperationContextScope(channel))
{
// set the session cookie to header
if (Cookie != null) {
HttpRequestMessageProperty request = new HttpRequestMessageProperty();
request.Headers["Cookie"] = cookie.ToString();
OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = request;
}
// execute method
var compiledMethod = method.Compile();
result = compiledMethod.Invoke();
}
}
// do different logic for FaultException, CommunicationException, TimeoutException
catch (Exception)
{
throw;
}
finally
{
CloseOrAbortServiceChannel(channel);
channel = null;
}
return result;
}
private static void CloseOrAbortServiceChannel(ICommunicationObject communicationObject)
{
bool isClosed = false;
if (communicationObject == null || communicationObject.State == CommunicationState.Closed)
return;
try
{
if (communicationObject.State != CommunicationState.Faulted)
{
communicationObject.Close();
isClosed = true;
}
}
catch (Exception)
{
throw;
}
finally
{
if (!isClosed)
AbortServiceChannel(communicationObject);
}
}
private static void AbortServiceChannel(ICommunicationObject communicationObject)
{
try
{
communicationObject.Abort();
}
catch (Exception)
{
throw;
}
}
}
所以这个简短的问题-可以初始化
通道
变量内部
ExecuteCommand
方法本身,虽然有可能定义,但应在内部执行哪种方法
执行命令
对于给定的频道?
我正试图完成这样的事情:
string color = "blue";
var cars = WcfHelper.ExecuteCommand<Car[], CarServiceSoapChannel>(channel => channel.GetCars(color));
甚至
string color = "blue";
var cars = WcfHelper.ExecuteCommand<CarServiceSoapChannel>(channel => channel.GetCars(color));
当然,任何其他代码改进建议都是受欢迎的,但不是强制性的。
附笔。
自动交换存储器
添加为
Service reference
在里面
Visual Studio
。因此,有些实体会自动为“汽车服务”生成,例如-
CarServiceSoapChannel
接口,
CarServiceSoapClient
当然还有
CarService
包含Web服务方法的接口。在上面的示例中,a
ChannelFactory
用于为
汽车服务频道
因此,下面是问题名称的来源:
Passing an interface method as a parameter
. 这可能有点误导,但我希望从描述本身就可以清楚地了解我试图完成的工作。
更新日期:2018年5月25日
我听从了@nvoigt的建议,能够达到我想要的结果:
public static TResult ExecuteCommand<TInterface, TResult>(Func<TInterface, TResult> method)
where TInterface : IClientChannel
{
TResult result = default(TResult);
IClientChannel channel = null;
try
{
channel = StrategyFactory.CreateChannel<TInterface>();
// init operation context
using (new OperationContextScope(channel))
{
// set the session cookie to header
if (Cookie != null)
Cookie.SetCookieForSession();
// execute method
result = method((TInterface)channel);
}
}
catch (Exception)
{
throw;
}
finally
{
CloseOrAbortServiceChannel(channel);
channel = null;
}
return result;
}
这已经达到了最初的目标。然而,这种方法有一个问题。要调用该方法,必须显式指定该方法的返回参数。
所以说,如果你想调用这个方法-写这是不够的:
var result = WcfHelper.ExecuteCommand<CarServiceSoapChannel>(channel => channel.IsBlue())
您必须具体说明,返回类型应为
boolean
var result = WcfHelper.ExecuteCommand<CarServiceSoapChannel, bool>(channel => channel.IsBlue())
我个人并不介意编写额外的代码,因为它仍然比我的初始方法实现有很大的优势,但是,我想知道新版本是否可以改进?
例如,当我只有一个普通的
TResult
键入方法-返回类型
<TResult>
可以省略。这不再是2个泛型的情况。无论如何,谢谢@
诺沃格特
!