Phidiax Tech Blog

Adventures in custom software and technology implementation.

Using the Microsoft Enterprise Library Validation Block in Azure Functions v1

For those using WCF services who need validation, you are likely familiar with the Microsoft Enterprise Library Validation Block (Microsoft Patterns and Practices) and the WCF behavior that makes service input validation pretty easy to setup (If not, there is a deep-dive on using the validation block here). Perhaps you want to make the jump into Azure Functions but want to keep your validation without having to recode it in any of the function language flavors. If that's the case, you've come to the right place!


Setting Up the Azure Function

For those not familiar, I will provide the steps here in creating the Azure Function app. If this is old hat for you, skip to the next section.

To create a new Azure Function app (which is an App Service), Use "More Services" to navigate to the App Services section:



Click Add and use the search bar to enter "Function App" to find the Microsoft Azure Function App option:



Select Function App, and click Create on the description window. Select a name, resource group, hosting plan (you can pay based on usage or just a general monthly hosting fee), and file storage account. If you choose to host in the app service plan, you need to select an app service that indicates location and hosting tier levels. You also must select a storage account for logging and triggers. If you choose to host in the usage plan ("Consumption Plan"), you must select the location and a storage account. In addition to storing logging and triggers, consumption plan based apps also use the storage account for the files being hosted for the function. In this example, I'll be hosting in Consumption Plan since it is far cheaper for the test volume I will be using to screenshot for this blog:



Once you click create and the application is created, we can pull up the new function app from App Services. From there, let's create a new C# HTTP Triggered function. Click the add button next to functions and select Webhook + API with CSharp as the language:



We now have a basic function that can pull from the posted body and query string to access the "name" field and return basic text based on that. Go ahead and click run to show that it builds and works:



You can see that there is code in the return clause which does some rudimentary "validation" of the name field. This is fine for a simple request like this, but for more complex data-points, coding a pile of validation here isn't ideal (or fun). That's where enterprise library comes in!


Setting Up the Validation Configuration

Before we can validate, we need to setup a class that contains the properties we expect to validate. For a simple demonstration, I have setup the following test class:

class ClassTest
{
    public string _value { get; set; }
    public string _name { get; set; }
}


To add that class to the function, paste it below the closing curly bracket for the Run method. Now that we have the class, we can parse the request body as JSON to obtain an instance of this type. Let's replace the dynamic data assignment line with the following:

// Get request body
var data = await req.Content.ReadAsAsync<ClassTest>();


Before we can setup a validation configuration, we need to obtain the type name of this built object. To do that, we can log the information for viewing during a test run by adding the following snippet after the data read above:

//You need the type name of the type to validate. This
//Needs to be used fully in the config as well to properly
//work!
log.Info(data.GetType().FullName);


Now let's run the function to ensure that the parsing of the JSON works, and we get the full type name to use in the configuration based validation rules. Note the log section at the bottom of the screen. You should see all logged information there, including the full type name logged using the code above:


We now know the full class name for putting into our validation configuration snippet: "Submission#0+ClassTest". With that information, let's use the App Service Editor to be able to add a folder to store our configuration, and a configuration file to store the validation setup (just like the app or web config would in a "normal" situation). App Service Editor is a web-based file editor for your hosted files available on the main function app account under "Platform Features":


Once in the App Service Editor, let's create a new folder to store our configuration(s) called ValidationConfig. Select a file in wwwroot (like host.json) then click the New Folder button on wwwroot and enter the name and press enter:


Now, select that new folder, and press the New File button on wwwroot and name it test.config and press enter:


We now have a file we can paste a valid configuration file into for our validation block to use. I have setup a validation block configuration that will make sure the _name field is not null and has one or more characters, and that the _value field can be parsed as a Decimal. Let's paste the following validation code into the config file.

Note: you don't have to manually create this XML as there is a visual tool that accompanies Enterprise Library to do this. You can download it here by downloading "EnterpriseLibrary6-binaries.exe". Note that it will expect you to run the PowerShell script to download the main Enterprise Library binaries from NuGet. This will fail because it is packaged with an old version of NuGet. Before running the PowerShell script, update the NuGet executable by running NuGet update -self, then the PowerShell script will work as-is.

<configuration>
  <configSections>
    <section name="validation" type="Microsoft.Practices.EnterpriseLibrary.Validation.Configuration.ValidationSettings, Microsoft.Practices.EnterpriseLibrary.Validation, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />
  </configSections>
  <validation>
    <type name="Submission#0+ClassTest"
      defaultRuleset="Validation Ruleset">
      <ruleset name="Validation Ruleset">
          <properties>
              <property name="_name">
                  <validator type="Microsoft.Practices.EnterpriseLibrary.Validation.Validators.NotNullValidator, Microsoft.Practices.EnterpriseLibrary.Validation, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                      name="Not Null Validator" />
                  <validator type="Microsoft.Practices.EnterpriseLibrary.Validation.Validators.StringLengthValidator, Microsoft.Practices.EnterpriseLibrary.Validation, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                      upperBound="1" lowerBound="1" lowerBoundType="Inclusive" upperBoundType="Ignore"
                      name="String Length Validator" />
              </property>
              <property name="_value">
                  <validator type="Microsoft.Practices.EnterpriseLibrary.Validation.Validators.TypeConversionValidator, Microsoft.Practices.EnterpriseLibrary.Validation, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                      targetType="System.Decimal, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
                      name="Type Conversion Validator" />
              </property>
          </properties>
      </ruleset>
    </type>
  </validation>
</configuration>


Using the Validation Against POSTed Data

Ok, so we have our new class and our validation configuration file setup. Now, we just need to read that configuration and use it to validate the object. The resulting ValidationResults object can be passed back directly on failure, or could be parsed and logged instead as desired.

First, we need to tell Azure Functions that we need the NuGet Enterprise Library Validation and Common libraries loaded. We do that by creating a file called "project.json" and providing the dependency information there. You can add a file to the function on the right side of the view in "View Files" by clicking Add and naming the new item project.json and hitting enter:

 


The following JSON will tell Azure Functions to load what we need. Paste it into project.json and save:

{"frameworks": {
    "net46":{
      "dependencies": {
        "EnterpriseLibrary.Common": "6.0.1304",
        "EnterpriseLibrary.Validation": "6.0.1304"
      }
    }
   }
}


To load the configuration file, we need to figure out our local path. Azure Functions doesn't seem to return the "correct" path when using the standard "HostingEnvironment.MapPath" or environment variable WEBROOT_PATH (someone please correct me if there is a good way of finding this in code), so we need to use the console to find our directory. The console link is available on the main function app account under "Platform Features". Let's use it to find where we are hosted from:


... and where the NuGet packages are hosted:



Based on this, we know that the ValidationConfig absolute path will be inside D:\home\site\wwwroot\ValidationConfig, and how to properly reference (see #r directive at the top of the snippet below) Enterprise Library from the NuGet download location. With that information, we can write the code to load the configuration into a validator and use it on the object. Additionally, we can return the validation results when the input is invalid, and run to completion when valid. Following is the final full Azure Function code snippet:

#r "D:\home\data\Functions\packages\nuget\enterpriselibrary.common\6.0.1304\lib\NET45\Microsoft.Practices.EnterpriseLibrary.Common.dll"
#r "D:\home\data\Functions\packages\nuget\enterpriselibrary.validation\6.0.1304\lib\NET45\Microsoft.Practices.EnterpriseLibrary.Validation.dll"
using System.Net;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Validation;

public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
    log.Info("C# HTTP trigger function processed a request.");
    
    // parse query parameter
    string name = req.GetQueryNameValuePairs()
        .FirstOrDefault(q => string.Compare(q.Key, "name", true) == 0)
        .Value;

    // Get request body
    var data = await req.Content.ReadAsAsync<ClassTest>();

    //You need the type name of the type to validate. This
    //Needs to be used fully in the config as well to properly
    //work!
    log.Info(data.GetType().FullName);

    //Create a file config loader, set that as our default Enterprise Library Validation config source
    FileConfigurationSource fcs = new FileConfigurationSource(
        @"D:\home\site\wwwroot\ValidationConfig\test.config");
    ValidationFactory.SetDefaultConfigurationValidatorFactory(fcs);

    //Create a validator from the factory and use it on our object. Results are in "test"
    var test = ValidationFactory.CreateValidator<ClassTest>().Validate(data);


    return !test.IsValid
        ? req.CreateResponse(HttpStatusCode.BadRequest, test)
        : req.CreateResponse(HttpStatusCode.OK, "Hello " + data._name);
}

class ClassTest
{
    public string _value { get; set; }
    public string _name { get; set; }
}


Save and Run!

Now we can save and test!

Let's run with what we know to be invalid request: an empty _name and empty _value fields:



We have a return of the validation errors serialized as JSON directly stating both fields as invalid.

Now let's try with a valid name but invalid value:



And we can run a fully valid value, and the normal response is returned:

Comments (2) -

  • Syed Zubair

    12/21/2017 7:28:02 AM | Reply

    I have a function app that is developed and deployed from Visual Studio, this function shows as readonly and I cannot add a new file. I have added the references in the visual studio solution but still it throws the file not found exception. How do I add the project.json in this case to references these Microsoft enterprise libraries.

    Thanks.
    Syed

    • Dean May

      1/24/2018 9:35:26 AM | Reply

      Syed,

      We noticed this too when attempting to use a prebuilt function. As far as I can tell when debugging locally, it looks like this is an issue with attempting to resolve the Enterprise Library assemblies by the Configuration loader. Instead of looking in directory with the function DLL, it appears to be looking to the function host executable directory, so it cannot find it.

      I tried using an XmlReader to load the configuration instead, but the Configuration subsystem is still attempting to load the enterprise libraries from the wrong location when instantiating the Validator.

      For now, you would need to use the in-code attributes to decorate the types you want to validate instead of loading the config.

      I will update this entry later this week to reflect this information. Thanks for bringing to my attention!

      Dean

Pingbacks and trackbacks (1)+

Loading

Privacy Policy  |  Contact  |  Careers

2009-2017 Phidiax, LLC - All Rights Reserved