I'm trying to use the Ionad plugin for Fody. I've created my substitution but the dependent code doesn't call the substitute.
Substitute
[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;
}
}
Dependent Method
[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();
}
}
}
Static dependencies tend to make it difficult to maintain and test code that is tightly coupled to them.
ASP.NET Web API provides extensibility points to be able to avoid having such dependencies. Mainly the
IDependencyResolverwhich is used for Dependency Injection in ASP.NET Web API 2.With that I would suggest converting that static utility into an abstraction or at least abstracting it behind an interface that can be replaced easily.
This will now allow for any number of implementations, especially stubs that can be used for unit testing if needed.
The dependent code would now be refactored to depend on the abstraction and not the implmentation which could be anything.
Just make sure to configure the Dependency Resolver with your IoC container of choice at start up.