<![CDATA[Jose Carlos Nuñez]]>https://www.josecdev.com/https://www.josecdev.com/favicon.pngJose Carlos Nuñezhttps://www.josecdev.com/Ghost 4.32Tue, 07 Jun 2022 18:46:42 GMT60<![CDATA[Asp net core action filters and requests html encoding]]>https://www.josecdev.com/asp-net-core-action-filters-request-html-encoding/629c5b902bccc50001928ef5Sun, 05 Jun 2022 09:43:57 GMT

Normally you need to accept text user input in your REST Apis, in that case XSS can become a security concern, you can but certainly shouldn’t rely on the frontend to send safe text input o to rendered it back properly for many reasons. The Asp Net MVC Framework (the classic controllers and views) does an html encoding when rendering the view models, but if you are using an Api based application or you want to make sure you only save sanitized input you will have to do this yourself. In this article I will explain what Filters are in the context of asp net and how we can apply them to make sure all requests are properly html encoded. You can follow along with the explanation or look at the source code here.

Filters

Let’s begin by explaining what Filters are, in asp net core a MVC filter is a piece of code that its being executed at specific stage in the request/response pipeline and they can inspect, change or stop the pipeline. You can have different types of Filters: Authorization Filters, Resource Filters, Actions filters Result filters and Exception, Filters (the last two are more useful when dealing with responses so let’s ignore them).

Authorization Filters can use the circuit braker pattern to prevent the action to be executed while  Resource Filters that are useful to implement patterns like caching and so on.

On the other hand, you have Action Filters which are executed after the model binding process and right before the controller’s action, meaning you will get a ActionArguments property containing the actual arguments that are going to be passes to the controller action making it a perfect fit for inspecting and modifying the request objects using reflection.

Action Filters

To create a custom action filter, you can need a class that implement the IActionFilter interface provided by the framework or you can derive the abstract class ActionFilterAttribute as this allows you to only implement the method you are interested in. Either way the you get the same contract.

public interface IActionFilter : IFilterMetadata
{
    void OnActionExecuting(ActionExecutingContext context);
    void OnActionExecuted(ActionExecutedContext context);
}
IActionFilter

After looking at the contract you can probably guess that OnActionExecuting is executed before the target controller action, while OnActionExecuted comes after. In this article we'll put the focus on the first method as given that we need to modify the request. The ActionExecutingContext has several properties that describe the action being executed, here is a list with the specific properties that we'll be using for quick reference.

Name Description
HttpContext Provides details of the current HTTP request and the HTTP response.
ActionArguments A dictionary of the arguments that will be passed to the action method (indexed by name).
ActionDescriptor Describes the action method.

The Code

Now that we now how this filters work let’s put this in practice and create one. First, we need to create a marking interface and an attribute.

public interface IRequireHtlmEncoding { }

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method |       
 AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class NeverEncodeAsHtmlAttribute : Attribute { }   
Contracts

We'll use the first interface to mark our request view models since html encoding may be a thing that you would not want to apply to the whole application. The attribute will allow us to skip a given property of the model or the entire action. Here is example how it can be used.

[ApiController]
[Route("api/v1/test")]
public class TestController : ControllerBase
{
   
    //Skip this action
    [HttpPost("model-ignore-all-attribute-on-action")]
    [NeverEncodeAsHtml]
    public void PostModelIgnoreAction([FromBody] TypedModel model)
    {
        ...
    }
}

//Every model that derive from this class will be included
public class RequestModelBase : IRequireHtlmEncoding { }

public class RequestModel : RequestModelBase
{
    //Only skip this field
    [NeverEncodeAsHtml]
    public string? NeverEncodeField { get; set; } = string.Empty;
}
How to use contracts

Of course, contracts don’t do magic so let’s create the filter itself.

public class HtmlEncodeActionFilterAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext context)
    {
	//To Do
    }
}
Html Encode Action Filter 

You can see that the class derives from the abstract class ActionFilterAttribute provided by the framework. The next step would be applying the filter only when a Post or Put request arrives.

public override void OnActionExecuting(ActionExecutingContext context)
{
    if (!HttpMethodApplies(context.HttpContext.Request))
        return;
}

private static bool HttpMethodApplies(HttpRequest request)
{
    var method = request.Method;
    return method == "POST" || method == "PUT";
}
Filter based on Http Request Method

To access the current http request you can access the HttpContext from ActionExecutingContext object. Then we need to check if the action has been marked with the NeverEncodeAsHtmlAttribute as that would be signaling that no encoding is required.

public override void OnActionExecuting(ActionExecutingContext context)
{
    ... 
    if (IsBeingExplicitMarkAsIgnored(context)) return;
}

private static bool IsBeingExplicitMarkAsIgnored(ActionExecutingContext context)
{
    return context.ActionDescriptor
    		  .EndpointMetadata
                  .Any(x => x is NeverEncodeAsHtmlAttribute);
}
Filter based on Action attributes

The ActionExecutingContext.ActionDescriptor.EndpointMetadata returns a list of the attributes applied in the action itself.  In the next listing I show you how to get access to the Parameters that are going to be passed to the action after the model binding has been applied.

public override void OnActionExecuting(ActionExecutingContext context)
{
    ... 
    var inspectArguments = context
    	.ActionArguments
        .Where(x => ShouldInspectObject(x.Value))
        .ToList();

    if (!inspectArguments.Any())
        return;
}

private static bool ShouldInspectObject(object? value)
{
    if (value is null)
        return false;

    bool hasIgnoreAttribute = value.GetType()
    	.GetCustomAttribute<NeverEncodeAsHtmlAttribute>() is not null;

    if (hasIgnoreAttribute)
        return false;

    return value is IRequireHtlmEncoding;
}

The list of arguments is contained in ActionExecutingContext.ActionArguments, the ShouldInspectObject makes sure that two conditions are meet: the Argument cannot be marked with NeverEncodeAsHtmlAttribute and it should implement the IRequireHtlmEncoding interface.

Now that we have the list of arguments to be updated, we need to start the introspection, lets create a method for that.

public override void OnActionExecuting(ActionExecutingContext context)
{
    ... 
    foreach (var argument in inspectArguments)
    {
        var value = argument.Value;
        switch (value) {
        case IRequireHtlmEncoding encodeObject:
            InspectAndEncodeObjectSringProperties(encodeObject);
            break;
        }
    }
}

private static void InspectAndEncodeObjectSringProperties(
    IRequireHtlmEncoding objectToEncodeStringProperties)
{
    // To Do
}
Start Arguments introspection

Before changing any property of the object, we need to make sure again that such property is not being mark with the same NeverEncodeAsHtmlAttribute, we can use reflection for that.

private static void InspectAndEncodeObjectSringProperties(
    IRequireHtlmEncoding objectToEncodeStringProperties)
{
    if (objectToEncodeStringProperties == null)
        return;

    var propertiesToInspect = objectToEncodeStringProperties.GetType()
              .GetProperties(BindingFlags.Public | BindingFlags.Instance)
              .Where(p => p.GetCustomAttribute<NeverEncodeAsHtmlAttribute>() is null)
              .ToList();

    foreach (var property in propertiesToInspect) {
        // To Do
    }
}
Get the properties that need to inspect

The next step is the actual encoding the property as you can see in the next listing.


private static void InspectAndEncodeObjectSringProperties(
    IRequireHtlmEncoding objectToEncodeStringProperties)
{
    ... 
    foreach (var property in propertiesToInspect)
    {
        string propertyName = property.Name;

        if (property.PropertyType == typeof(string)) {
            if (property.SetMethod != null) {
                string? strValue = (string?) property.GetValue(objectToEncodeStringProperties);
                property.SetValue(objectToEncodeStringProperties, HtmlEnconde(strValue));
            }
        }
    }
}

private static string? HtmlEnconde(string? original)
{
    return original is null ? null : WebUtility.HtmlEncode(original);
}
Actual html encoding

Before changing a property, we need to make sure that it has some sort of ‘set’, then we can modify it with the same value but this time properly encoded, the actual encoding can be done through the WebUtility class. Lastly let’s deal with nested objects.

private static void InspectAndEncodeObjectSringProperties(
    IRequireHtlmEncoding objectToEncodeStringProperties)
{
    ... foreach (var property in propertiesToInspect)
    {
        string propertyName = property.Name;

        if (property.PropertyType == typeof(string)) 
        {
            ...
        } 
        else
        {
            object? propertyValue
                = property.GetValue(objectToEncodeStringProperties);
            if (ShouldInspectObject(propertyValue)) 
            {
                switch (propertyValue) 
                {
                	case IRequireHtlmEncoding encodeInnerObject:
                   	InspectAndEncodeObjectSringProperties(encodeInnerObject);
                    break;
                }
            }
        }
    }
}
Dealing wih nesteed objects

Reflection and recursiveness are our friends here, we basically need check value and based on its type call the same InspectAndEncodeObjectSringProperties method. We’ve just have finished with the filter, but we need to register the filter with the container.

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers(options => {
        options.Filters.Add(new HtmlEncodeActionFilterAttribute());
    });
}
Add the filter to the IoC Container

To register the filter, you need to added it to the Filters collection of the MvcOptions object while registering the controllers.

Summary

Actions filters, and filters in general are part of the MVC pipeline and can be useful when it comes to expanding the framework itself and are not that difficult to implement. Today we saw a practical example of how you can do one filter to make sure request are safely using html encoding without polluting the code in your controllers or you application. Hope you find it useful and remember that you can check out the source code here.

]]>
<![CDATA[Compile and evaluate mathematical expressions with C#]]>https://www.josecdev.com/compile-and-evaluate-mathematical-expressions-with-c-sharp/623715d80cd1660001d8dbc3Sun, 20 Mar 2022 12:10:21 GMT

Today I will be talking about how you can evaluate mathematical expressions and functions using C# and more specifically using a library called JustFunctional.

What is Just Functional

Just Functional is a .NET evaluator, its built and maintained by me. It has a very opinionated design and a user-friendly API that allows you to customize certain things like operators, constants or take control of some aspect like disabling variables entirely.

I don’t want to make a long post and we won’t cover all the things you can do with this library; you can have a look at link to the documentation above get more details.

What are we doing then?

We are going to be build a console based application that ask the user for a input function like: f(x,y) = X+Y and  for the corresponding values E.g. X=3 & Y=4. Then with this information then we are going to parse and try to evaluate the function. You can find the entire source code here if you don’t want to follow along.

The Code

Without any further delay let’s use the library with this illustrative example. I’m going to assume you have an empty console application and I will be using .NET 6 in this case just because it requires less boilerplate code due to features like implicit usings and top-level statements but you can any other version of .NET.

The first step would be installing the nuget package, its named JustFunctional.Core, one way to do this is by using the dotnet cli, go ahead browse to folder where the .csproj is located, open a terminal and type the following command:

dotnet add package JustFunctional.Core --version 2.0.2

Then let’s jump straight to using the library I will explain everything afterwards:

using JustFunctional.Core;

string expression = AskAndGetInputExpression();
Dictionary<string, decimal> variablesWithValues = AskAndGetInputVariablesWithValues();


var functionFactory = FunctionFactoryBuilder.ConfigureFactory(options =>
{
    options
        .WithEvaluationContextVariablesProvider()
        .WithCompiledEvaluator();
});

var variables = new PredefinedVariablesProvider(variablesWithValues.Keys.ToArray());
TryCreateFunctionResult createResult = functionFactory.TryCreate(expression, variables);

if (!createResult.Success)
{
    Console.WriteLine($"The expression could not be parsed because: {string.Join(", ", createResult.Errors)}");
    return;
}
var evalutaionContext = new EvaluationContext(variablesWithValues);
var result = await createResult.Function.EvaluateAsync(evalutaionContext);

Console.WriteLine(result);
Console.ReadLine();
Program.cs

The first two lines you can see the calls to AskAndGetInputExpression() and AskAndGetInputVariablesWithValues() methods, they simply read the expression and the variables with values respectively (Ex X=3;Y=4) from the console and I will include them for completeness at the end since is just string manipulation.

In the next statement we create a FunctionFactory, although you can create a function directly, if there is some kind of syntax error on the expression you will get exceptions, so when you need features like syntax validation or customizing certain components is a good idea to use the FunctionFactoryBuilder.ConfigureFactory(...) method.

You sure noticed two other statements while configuring the factory. The first one, WithEvaluationContextVariablesProvider() means that you will defer passing variables (or variables and values) whenever you are evaluating/validating. The other, WithCompiledEvaluator() tells the factory to compile function and expression once rather than doing it every time you evaluate. You could have omitted both of them since these are the default values, I decided to include them because this is the way you can change how the library behaves.

The next line functionFactory.TryCreate(expression, variables) will try to parse the expression and will yield an object with a Boolean property called Success. When the parsing phase fails (Success = false) you will find error description in the Errors property.

Once you make sure that expression is parsed correctly you can use Evaluate() or EvaluateAsync() passing the variables along with their corresponding values to get the result of evaluating the function.

Boilerplate Code

Finally, for completeness here are the AskAndGetInputExpression() and AskAndGetInputVariablesWithValues() methods that take care of reading the user input:


string AskAndGetInputExpression()
{
    Console.WriteLine("Enter the expression to evaluate: (E.g. X+Y)");
    var expression = Console.ReadLine() ?? throw new Exception("You need to suply a value");
    return expression;
}

Dictionary<string, decimal> AskAndGetInputVariablesWithValues()
{
    Console.WriteLine("Enter the expression's variables: (E.g. X=3;Y=4)");
    var splittedVariables = Console.ReadLine()?
        .Split(';', StringSplitOptions.RemoveEmptyEntries) ?? new string[0];
    var variablesWithValues = splittedVariables
        .Select(x => x.Split('=', StringSplitOptions.RemoveEmptyEntries))
        .ToDictionary(x => x.First(), v => decimal.Parse(v.Last()));
    
    return variablesWithValues;
}

Summary

JustFunctional is a .Net evaluator that with a few lines of codes allows you to compile and evaluate mathematical expressions and functions within your application, sure there are more robust libraries out there and with many more features but if all you need is some simple math evaluator you can give it a try.

In this post I tried to cover a happy path for Just Functional, but there are more things you can do with it, make sure visit the docs to learn more or have a look at example code here.

Lastly your feedback is appreciated you can certainly open a bug, a feature request or make a contribution by using the library's repository.

Bye!

]]>