我正在使用由@jweber
创建的名为WcfClientProxyGenerator的库我使用nuget生成针对服务的代理。一切正常,这里是一个代理类:
using Silly.Services.CarPark.Logging;
using Silly.Services.CarPark.ServiceContracts.Common.v1;
using log4net;
using System.Linq;
using System.Threading.Tasks;
using WcfClientProxyGenerator;
namespace Silly.Services.CarPark.Client
{
public class RequestManager
{
private static Log4NetLoggingAdapter systemLogger;
private static IRequestService proxy = null;
public RequestManager()
{
if (systemLogger == null)
{
LoggerSetup.Configure(Constants.ModuleNameForLogging);
systemLogger = new Log4NetLoggingAdapter(LogManager.GetLogger(typeof(RequestManager)));
}
proxy = WcfClientProxy.Create<IRequestService>(c =>
{
c.SetEndpoint("BasicHttpBinding_IRequestService");
c.OnCallBegin += (sender, args) => { };
c.OnBeforeInvoke += (sender, args) =>
{
systemLogger.Write(string.Format("{0}.{1} called with parameters: {2}", args.ServiceType.Name, args.InvokeInfo.MethodName, string.Join(", ", args.InvokeInfo.Parameters)), Core.EventSeverity.Verbose);
};
c.OnAfterInvoke += (sender, args) =>
{
systemLogger.Write(string.Format("{0}.{1} returned value: {2}", args.ServiceType.Name, args.InvokeInfo.MethodName, args.InvokeInfo.ReturnValue), Core.EventSeverity.Verbose);
};
c.OnCallSuccess += (sender, args) =>
{
systemLogger.Write(string.Format("{0}.{1} completed successfully", args.ServiceType.Name, args.InvokeInfo.MethodName));
};
c.OnException += (sender, args) =>
{
systemLogger.Write(string.Format("Exception during service call to {0}.{1}: {2}", args.ServiceType.Name, args.InvokeInfo.MethodName, args.Exception.Message), args.Exception, Core.EventSeverity.Error);
};
});
}
}
}
过了一会儿,我发现自己还有三个服务和三个代理。我看到我重复所有四个类的构造函数中的任何内容,并且很难跟踪更改。现在,记录的数量是裸的,但这种情况在不断变化。还有三项服务即将开始。
有没有办法使用Class来取出公共代码?
答案 0 :(得分:2)
依赖注入并未解决代码重复的主要问题,因为systemLogger
和proxy
都依赖于服务接口的类型,在本例中为IRequestService
。因此,即使您从外部传递这些内容&#34;,您仍然需要为要构建的每个服务接口设置不同的代码,以创建传递的对象。
泛型确实是捕捉共性的方法,因为每个服务的重复代码的唯一区别是接口类型。我将使用通用基类,并从中派生每个服务类,类似于我在下面显示的内容。
出于可测试性原因,您可能仍需要考虑使用依赖项注入来避免新增日志记录适配器。但这是另一个问题。
基础课程
using log4net;
using System.Linq;
using System.Threading.Tasks;
using WcfClientProxyGenerator;
using Silly.Services.CarPark.Logging;
namespace Silly.Services.Carpark
{
public class ClientBase<TClient> where TClient : class
{
private static Log4NetLoggingAdapter systemLogger;
private static TClient proxy;
public ClientBase(string binding)
{
if (systemLogger == null)
{
LoggerSetup.Configure(Constants.ModuleNameForLogging);
systemLogger = new Log4NetLoggingAdapter(LogManager.GetLogger(this.GetType()));
}
proxy = WcfClientProxy.Create<TClient>(c =>
{
c.SetEndpoint(binding);
c.OnCallBegin += (sender, args) => { };
c.OnBeforeInvoke += (sender, args) =>
{
systemLogger.Write(string.Format("{0}.{1} called with parameters: {2}", args.ServiceType.Name, args.InvokeInfo.MethodName, string.Join(", ", args.InvokeInfo.Parameters)), Core.EventSeverity.Verbose);
};
c.OnAfterInvoke += (sender, args) =>
{
systemLogger.Write(string.Format("{0}.{1} returned value: {2}", args.ServiceType.Name, args.InvokeInfo.MethodName, args.InvokeInfo.ReturnValue), Core.EventSeverity.Verbose);
};
c.OnCallSuccess += (sender, args) =>
{
systemLogger.Write(string.Format("{0}.{1} completed successfully", args.ServiceType.Name, args.InvokeInfo.MethodName));
};
c.OnException += (sender, args) =>
{
systemLogger.Write(string.Format("Exception during service call to {0}.{1}: {2}", args.ServiceType.Name, args.InvokeInfo.MethodName, args.Exception.Message), args.Exception, Core.EventSeverity.Error);
};
});
}
// The following class property exposes static private var
// to derived classes, as read-only.
protected TClient Proxy { get { return proxy; } }
}
}
派生服务类
using Silly.Services.CarPark;
using Silly.Services.CarPark.ServiceContracts.Common.v1;
using log4net;
using System.Linq;
using System.Threading.Tasks;
using WcfClientProxyGenerator;
namespace Silly.Services.CarPark.Client
{
public class RequestManager : ClientBase<IRequestService>, IRequestService
{
public RequestManager() :
base("BasicHttpBinding_IRequestService")
{
}
// Implementation of IRequestService methods
public string Alpha(...) {
return Proxy.Alpha(...);
}
public void Beta(...) {
Proxy.Beta(...);
}
}
}
答案 1 :(得分:1)
你自己上来了什么?我的意思是,应该直截了当地做这样的事情。
Create方法接受Action<IRetryingProxyConfigurator>
作为参数,因此我将构建一个类似
void ConfigureLogging(IRetryingProxyConfigurator proxyConfigurator)
{
proxyConfigurator.OnBeforeInvoke += (sender, args) =>
{
systemLogger.Write(string.Format("{0}.{1} called with parameters: {2}", args.ServiceType.Name, args.InvokeInfo.MethodName, string.Join(", ", args.InvokeInfo.Parameters)), Core.EventSeverity.Verbose);
};
}
并称之为:
proxy = WcfClientProxy.Create<IRequestService>(c =>
{
c.SetEndpoint("BasicHttpBinding_IRequestService");
ConfigureLogging(c);
}
尽可能多地重复代码重复代码并形成一个模式。您可以构建一个通用工厂,它接受服务接口作为类型参数,并在该类中进行所有模板化。
答案 2 :(得分:1)
请注意,鉴于此处正在创建所有绑定,所有这些服务都必须实现通用接口。使用它作为T,你应该没有太多的重构
protected void Page_Load(object sender, EventArgs e) {
BLSecurity BLSecurity = new BLSecurity();
wk_Gebruiker gebruiker = (wk_Gebruiker)Session["gebruiker"];
if (gebruiker != null) {
LabelTest.Text = gebruiker.voornaam;
} else {
LabelTest.Text = "no name";
}
BLSecurity.Gebruiker = gebruiker;
...
}
这可能无法编译,您可能需要更改内容,但我认为意图应该在那里