我试图使用Ionad plugin for Fody。我创建了我的替换,但是依赖代码没有调用替换。
[StaticReplacement(typeof(AppUtils))]
public static class AppUtilsSubsitute
{
public static void LogException(string func, Exception ex) => Write("Exception", ex.ToJson());
public static void LogError(string err) => Write("Error", err);
public static void LogInfo(string info) => Write("Info", info);
public static void LogWarning(string info) => Write("Warning", info);
public static void LogCypherQuery(string func, ICypherFluentQuery query) => Write(func, query.ToJson());
static void Write(string logType, string message)
{
var dictionary = new Dictionary<string, string> { { logType, message } };
var assembly = Assembly.GetExecutingAssembly();
using (var writer = new StreamWriter(assembly.Location + "Machine.Specifications.log"))
{
writer.Write(dictionary.ToJson());
}
}
public static Dictionary<string, string> Log()
{
var assembly = Assembly.GetExecutingAssembly();
Dictionary<string, string> content;
using (var reader = new StreamReader(assembly.GetManifestResourceStream("Machine.Specifications.log")))
{
content = JsonConvert.DeserializeObject<Dictionary<string, string>>(reader.ReadToEnd());
}
return content;
}
}
[AttributeUsage(AttributeTargets.Method)]
public class EnsurePresencesOfAttribute : ActionFilterAttribute
{
internal virtual string Required { get; }
internal virtual string Param { get; }
public EnsurePresencesOfAttribute(string required = "", string param="request")
{
Required = required;
Param = param;
}
public override void OnActionExecuting(HttpActionContext actionContext)
{
Dictionary<string, object> model = actionContext.ActionArguments;
if (model == null || model.Count == 0 || !model.ContainsKey(Param))
{
ValueError(actionContext, $"{Param} parameter");
return;
}
foreach (var requirement in Required.Split(',').Select(e => e.Trim()))
{
if (model[requirement] == null)
{
ValueError(actionContext, requirement);
return;
}
}
base.OnActionExecuting(actionContext);
}
public override Task OnActionExecutingAsync(HttpActionContext context, CancellationToken token)
{
Dictionary<string, object> model = context.ActionArguments;
if(model == null || model.Count == 0 || !model.ContainsKey(Param))
{
ValueError(context, $"{Param} parameter");
return Task.FromResult(0);
}
foreach (var requirement in Required.Split(',').Select(e => e.Trim()))
{
if (model[requirement] == null)
{
ValueError(context, requirement);
Task.FromResult(0);
}
}
return base.OnActionExecutingAsync(context, token);
}
private static void ValueError(HttpActionContext context, string requirement)
{
var action = context.ActionDescriptor.ActionName;
AppUtils.LogError($"{action} Failed : Missing Required Attribute {requirement}. ");
using (var controller = new BaseApiController { Request = new HttpRequestMessage() })
{
controller.Request.Properties.Add(HttpPropertyKeys.HttpConfigurationKey, new HttpConfiguration());
context.Response = controller.InvalidInputResponse();
}
}
}
答案 0 :(得分:2)
静态依赖性往往使维护和测试与它们紧密耦合的代码变得困难。
ASP.NET Web API提供了可扩展性点,以避免出现这种依赖关系。主要是用于Dependency Injection in ASP.NET Web API 2的IDependencyResolver
。
有了这个,我建议将静态实用程序转换为抽象,或者至少将其抽象为可以轻松替换的接口。
public interface ILogger {
void LogException(string func, Exception ex);
void LogError(string err);
void LogInfo(string info);
void LogWarning(string info);
void LogCypherQuery(string func, ICypherFluentQuery query);
Dictionary<string, string> Log();
}
这将允许任意数量的实现,尤其是可以在需要时用于单元测试的存根。
public class AppUtilsSubsitute : ILogger {
public void LogException(string func, Exception ex) => Write("Exception", ex.ToJson());
public void LogError(string err) => Write("Error", err);
public void LogInfo(string info) => Write("Info", info);
public void LogWarning(string info) => Write("Warning", info);
public void LogCypherQuery(string func, ICypherFluentQuery query) => Write(func, query.ToJson());
static void Write(string logType, string message) {
var dictionary = new Dictionary<string, string> { { logType, message } };
var assembly = Assembly.GetExecutingAssembly();
using (var writer = new StreamWriter(assembly.Location + "Machine.Specifications.log")) {
writer.Write(dictionary.ToJson());
}
}
public Dictionary<string, string> Log() {
var assembly = Assembly.GetExecutingAssembly();
Dictionary<string, string> content;
using (var reader = new StreamReader(assembly.GetManifestResourceStream("Machine.Specifications.log"))) {
content = JsonConvert.DeserializeObject<Dictionary<string, string>>(reader.ReadToEnd());
}
return content;
}
}
依赖代码现在将被重构为依赖于抽象而不是可能是任何东西的实施。
private static void ValueError(HttpActionContext context, string requirement) {
var httpConfiguration = context.RequestContext.Configuration;
var resolver = httpConfiguration.DependencyResolver;
var logger = resolver.GetService(typeof(ILogger));
var action = context.ActionDescriptor.ActionName;
logger.LogError($"{action} Failed : Missing Required Attribute {requirement}. ");
using (var controller = new BaseApiController { Request = new HttpRequestMessage() }) {
//USE THE GLOBAL HTTPCONFIGURATION ALREADY ASSOCIATED WITH THE
//REQUEST INSTEAD OF CREATING A NEW ONE THAT HAS NONE OF THE
//WEB API CONFIG THAT WOULD HAVE BEEN ADDED AT STARTUP
controller.Request.Properties.Add(HttpPropertyKeys.HttpConfigurationKey, httpConfiguration);
context.Response = controller.InvalidInputResponse();
}
}
确保在启动时使用您选择的IoC容器配置Dependency Resolver。
在
DependencyResolver
属性上设置依赖项解析器 全局HttpConfiguration
对象。以下代码向Unity注册
ILogger
接口 然后创建一个UnityResolver
。public static void Register(HttpConfiguration config) { var container = new UnityContainer(); container.RegisterType<ILogger, AppUtilsSubsitute>(new HierarchicalLifetimeManager()); config.DependencyResolver = new UnityResolver(container); // Other Web API configuration not shown. }