.Net Code Monkey RSS 2.0
 Saturday, 27 August 2016

Localising Javascript Resource Files in ASP.Net MVC


Localising website text in ASP.Net projects is trivial when carried out server-side using resource files, but what do you do when you need localised text served from the client side? In previous projects I have served up the localised text as parameters which my javascript is initialised with by placing a call to my init() mehtod in my MVC view and populating the parameters with values from the ViewModel. This is fine if you don't have much text to localise but what if you do?

In this article I'd like to present one option which I have recently used. So I'll start with a very basic out of the box ASP.Net MVC application. Lets use javascript to pop up a message on the home page and we will have a look at options for localising that. First lets replicate our "Views" structure and create a "Home" folder within the "Scripts" folder. Then add a javascript file to it with the filename "app.home.index.js". This will be the script that holds client side functionality for the "Index" view of the "Home" controller.

We will first check the "app" namespace is defined and create it if it is not, and then the same for the "app.home" namespace. Then we will create the object that will hold functionality for the "Home\Index" page. Before we go "fully resourced filed" lets take a look at how previosuly I may have approached this, and then we will make improvements as we go along.

if (typeof app === "undefined") {
    var app = {};
}
if (typeof app.home === "undefined") {
    app.home = {};
}
app.home.index = {

};

Within the "index" object we will create a field "message" to hold a message we are going to display and an init function which will take a message as a parameter and populate the message field from it. We will then add a function which will display the message to the user in a javascript popup.

app.home.index = {
    message: "",

    init: function(message) {
        this.message = message;
    },

    promptUser: function() {
        alert(this.message);
    }
};

Lets create a "Resources" folder in the root of the web application project, and within this a "Home" folder. Within the "Home" folder we will create resource file called "Index" for the content of the `Home/Index` view. In this file we will add a string resource called "Message" and set the value to "Hello World". We must change the "Access Modifier" of the file to "Public". While we are here lets move the "ASP.NET is a free web framework for building great Web sites and Web applications using HTML, CSS and JavaScript." test into the resource file with the name "SubHeader" so we can reference this text in the view.

|   | Name      | Value                                                                                                             |  Comment |
|---|-----------|-------------------------------------------------------------------------------------------------------------------|----------|
| > | Message   | Hello World                                                                                                       |          |
|   | SubHeader | ASP.NET is a free web framework for building great Web sites and Web applications using HTML, CSS and JavaScript. |          |

Lets open the default `Home/Index` MVC view and remove all but the "jumbotron" message. Add a using at  the top of the view `@using Blogs.LocalisingJavascriptResourceFiles.UI.Resources.Home` to import the home page resources namespace. Lets change the sub header to use the resource file. Then we can add a scripts section to reference the javascript file for this view and initialise it using the resource file content, and then call the `promptUser()` to show the message.

@using Blogs.LocalisingJavascriptResourceFiles.UI.Resources.Home
@{
    ViewBag.Title = "Home Page";
}

<div class="jumbotron">
  <h1>ASP.NET</h1>
  <p class="lead">@Index.SubHeader</p>
</div>

@section Scripts{
  <script src="@Url.Content(" temp_src="@Url.Content("~/Scripts/Home/app.home.index.js")"></script>
  <script>
    app.home.index.init("@Html.Raw(Index.Message)");
    app.home.index.promptUser();
  </script>
}
Run the application and all going well you should have a javascript alert pop up with "hello World".

So that's all great we have a message in English declared in a C# resource file and use this to populate the file in the javasript. So now lets add another culture resource file. Copy the "Index.resx" file and paste a copy in the same "Resources/Home" folder location. Change the filename to "index.de-DE.resx" so we have a file for German speaking countries. Open the file and translate the two text resources to say "Hallo Welt" for the `Message`and "ASP.NET ist eine kostenlose Web-Framework für den Aufbau von großen Web -Sites und Web -Anwendungen mit HTML, CSS und JavaScript." for the `SubHeader`.

We now need to force the culture to "de-DE" in the web.Config file. Add a `globalization` node inside `system.web`.

  <system.web>
    <globalization uiCulture="de-DE" culture="de-DE" />
  </system.web>


Lest run the app again, both the sub heading *but* more importantly the javascript alert should display in Deutch (German). So this is great but what happens if we have a few messages that are displayed from javascript and need to be localised. Well first step you may decide to add another parameter to the javascript `app.home.index.init()` method...

Lest create a new string resource in the two C# resource files with the name `Message2` and the values "How are you?" and "Wie geht es dir?" respectively for the default and "de-DE" versions. Lets add a second message field to the javascript `app.home.index` object and call it inspiringly... `message2`. We need to initialise this from the `init()` function along with the original message.

app.home.index = {
    message: "",
    message2: "",

    init: function (message, message2) {
        this.message = message;
        this.message2 = message2;
    },

    promptUser: function () {
        alert(this.message);
        alert(this.message2);
    }
};

And in the "Index "view..

   app.home.index.init("@Html.Raw(Index.Message)", "@Html.Raw(Index.Message2)");

Ok so this works but already it's getting kind of unwieldy and the more text that is needed the worse it will get. Now you can get around this slightly using the JQuery's `extend` method like `options = $.extend(defaults, options);` to overwrite default paceholder strings with those passed in through an "options" parameter of the `app.home.index.init()` method. But this is still unwieldy as in your view you will need to instatiate the options and set the properties from the C# resource file, and this could become quite a high quantity in time.

What might be nice would be to have a javascript equivelent of the C# resources file that has the correctly localised strings embedded. So lets create a javascript resource file and see how things pan out. In the "Scripts\Home" folder add a javascript file called "app.home.index.resource.js". For the time being just populate the two resource message fields with the english values.

if (typeof app === "undefined") {
    var app = {};
}
if (typeof app.home === "undefined") {
    app.home = {};
}
if (typeof app.home.index === "undefined") {
    app.home.index = {};
}
app.home.index.resources = {
    message: "Hello World",
    message2: "How are you?"
};

Add a new method to the `app.home.index` object called `promptUser2` which will reference the strings in the  resource file directly.

    promptUser2: function () {
        alert(this.resources.message);
        alert(this.resources.message2);
    }

Switching  back to the "Index" view, comment out the call to `app.home.index.promptUser();` and add a call to `app.home.index.promptUser2();` instead. Add a script reference to the javascript index resource file after the main javascript index file.

@section Scripts{
  <script src="@Url.Content(" temp_src="@Url.Content("~/Scripts/Home/app.home.index.js")"></script>
  <script src="@Url.Content(" temp_src="@Url.Content("~/Scripts/Home/app.home.index.resource.js")"></script>
  <script>
    app.home.index.init("@Html.Raw(Index.Message)", "@Html.Raw(Index.Message2)");
    //app.home.index.promptUser();
    app.home.index.promptUser2();
  </script>
}
Remember to comment out the "globalization" node in the "web.Config" file to return to your current culture, and then you can test the app. Obviously it will just return the hard coded non-localised strings in the js resources file at this present time. Now lets look at getting these values localised. So to do this we are going to turn the "magic strings" in the resource file into named placeholders that directly correspond to the names in the C# resource file. We will wrap the names in curly braces to help identify them when we read them later in the server code.

if (typeof app === "undefined") {
    var app = {};
}
if (typeof app.home === "undefined") {
    app.home = {};
}
if (typeof app.home.index === "undefined") {
    app.home.index = {};
}
app.home.index.resources = {
    message: "{Message}",
    message2: "{Message2}"
};
So next up we need a class that can covert our javascript files with named place holders into a script with the appropriate culture resource strings inserted. Lets add a folder called Helpers to the root of the "Blogs.LocalisingJavascriptResourceFiles.UI" project. However before we can "covert" the file we need to "load" the file contents and to carry this out we will create a class called `JavascriptResourceFileContentLoader`. The class takes the base javascript folder name, the name of the controller and the name of the view in the constructor. After some simple guard clause are passed the values are cached. The `Load` method builds the file path, checks a file exists at the path and opens the file without a file lock and then loads the content into the `Output` poperty. Notice the `Load` method returns the current instance. It could have been a void, but instead by return the same instance it allows a fluid API. Not everyone's cup of tea, I know. If the file path does not lead to a file then a `FileNotFoundException` is thrown from the `EnsureFileExists` method.

    public class JavascriptResourceFileContentLoader
    {
        private const char BackSlash = '\\';
        private readonly string _baseScriptFolderPath;
        private readonly string _controllerName;
        private readonly string _viewName;
        private string _resourceFilePath;
        public string Output { get; private set; }

        public JavascriptResourceFileContentLoader(string baseScriptFolderPath, string controllerName, string viewName)
        {
            if (string.IsNullOrWhiteSpace(baseScriptFolderPath)) throw new ArgumentNullException("baseScriptFolderPath");
            if (string.IsNullOrWhiteSpace(controllerName)) throw new ArgumentNullException("controllerName");
            if (string.IsNullOrWhiteSpace(viewName)) throw new ArgumentNullException("viewName");

            _baseScriptFolderPath = baseScriptFolderPath;
            _controllerName = controllerName;
            _viewName = viewName;
        }

        public JavascriptResourceFileContentLoader Load()
        {
            BuildFilePath();
            EnsureFileExists();
            LoadFileWithNoLock();

            return this;
        }

        private void BuildFilePath()
        {
            var pathBuilder = new StringBuilder();
            pathBuilder.Append(_baseScriptFolderPath);
            var lastCharIsBackSlash = (pathBuilder[pathBuilder.Length - 1] == BackSlash);
            if (!lastCharIsBackSlash) pathBuilder.Append(BackSlash);
            pathBuilder.Append(_controllerName);
            pathBuilder.Append(BackSlash);
            pathBuilder.Append("app.");
            pathBuilder.Append(_controllerName.ToLower());
            pathBuilder.Append(".");
            pathBuilder.Append(_viewName.ToLower());
            pathBuilder.Append(".resource.js");

            _resourceFilePath = pathBuilder.ToString();
            var baseDirectory = AppDomain.CurrentDomain.BaseDirectory;
            _resourceFilePath = string.Concat(baseDirectory, _resourceFilePath);

        }

        private void EnsureFileExists()
        {
            var fileExists = File.Exists(_resourceFilePath);
            if (!fileExists) throw new FileNotFoundException(_resourceFilePath + " does not exist. ");
        }

        private void LoadFileWithNoLock()
        {
            string content;
            using (var fileReadStream = new FileStream(_resourceFilePath,
                FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
            )
            {
                using (StreamReader fileStreamReader = new StreamReader(fileReadStream))
                {
                    content = fileStreamReader.ReadToEnd();
                }
            }

            Output = content;
        }
    }


Now we have a class that can read the content of the javascript resource file, we now need a class to manipulate that content and mutate the named placeholders in culture specific values, i.e. replacing the placeholders with values from the appropriate C# resource file. For this we will use the `JavascriptResourceFileContentCulturiser`. Nice name? Not really but I could not come up with anything more descriptive!

The first point of note is the class has some static members which hold the assembly and construct and hold the namespace. These are static as they will always be the same for all instances of the class, regardless of what parameters the class is constructed with. The class takes the unadulterated javascript file content, the name of the controller and the name of the view in the constructor. After some simple guard clause are passed the values are cached. The main method is `Culturise` which gets a reference to the ResourceManager for the we are intending to use, splits the content into lines and iterates through them looking for one of our names placeholders. If one is found on the line then it is compared with the named resource strings and if a matching resource string is found the placeholder name replaced with the resource string value. All of the content lines, mutated or otherwise are packed into a StringBuilder and forced into the `Output` property.

    public class JavascriptResourceFileContentCulturiser
    {
        #region Static Members

        private static string _nameSpace;
        private static Assembly _assembly;
        private static readonly Regex PlaceHolderRegex = new Regex("{.+?}");
        private static readonly char[] LineSeparators = { '\n', '\r' };
        private const string ResourcesFolderName = "Resources";
        private const char PlaceHolderStartChracter = '{';
        private const char PlaceHolderEndChracter = '}';
        private const char NamespaceDelimiter = '.';

        static JavascriptResourceFileContentCulturiser()
        {
            SetAssembly();
            BuildNameSpace();
        }

        private static void SetAssembly()
        {
            _assembly = Assembly.GetExecutingAssembly();
        }

        private static void BuildNameSpace()
        {
            _nameSpace = _assembly.GetName().Name;
        }

        #endregion

        #region Instance members

        private readonly string _content;
        private readonly string _controllerName;
        private readonly string _viewName;
        public string Output { get; private set; }

        public JavascriptResourceFileContentCulturiser(string content, string controllerName, string viewName)
        {
            if (string.IsNullOrWhiteSpace(content)) throw new ArgumentNullException("content");
            if (string.IsNullOrWhiteSpace(controllerName)) throw new ArgumentNullException("controllerName");
            if (string.IsNullOrWhiteSpace(viewName)) throw new ArgumentNullException("viewName");

            _content = content;
            _controllerName = controllerName;
            _viewName = viewName;
        }

        public JavascriptResourceFileContentCulturiser Culturise()
        {
            var type = GetTypeForFullyQualifiedName();
            if (type == null) throw new InvalidOperationException(string.Concat(_viewName, " resource not found "));

            var resourceManager = new ResourceManager(type);
            var scriptBuilder = new StringBuilder();

            string[] originalContentAsLines = _content.Split(LineSeparators, StringSplitOptions.RemoveEmptyEntries);
            foreach (var originalContentLine in originalContentAsLines)
            {
                if (string.IsNullOrWhiteSpace(originalContentLine)) continue; // Should not actuall happen due to string split options.

                var matches = PlaceHolderRegex.Matches(originalContentLine);
                var haveMatches = matches.Count > 0;
                string finalScriptLine = originalContentLine;

                if (haveMatches)
                {
                    string replacementValue;
                    var firstMatch = matches[0].ToString();
                    var haveReplacableValue = TryGetReplacementValue(firstMatch, resourceManager, out replacementValue);
                    if (haveReplacableValue)
                    {
                        finalScriptLine = originalContentLine.Replace(firstMatch, replacementValue);
                    }
                }

                scriptBuilder.AppendLine(finalScriptLine);
            }

            Output = scriptBuilder.ToString();
            return this;
        }

        private Type GetTypeForFullyQualifiedName()
        {
            var fullyQualifiedName = string.Concat(_nameSpace, NamespaceDelimiter, ResourcesFolderName,
                NamespaceDelimiter, _controllerName, NamespaceDelimiter, _viewName);
            var type = _assembly.GetType(fullyQualifiedName);

            return type;
        }

        private static bool TryGetReplacementValue(string initialValue,
            ResourceManager resourceManager, out string replacementValue)
        {
            var placeHolderValue = initialValue.TrimStart(PlaceHolderStartChracter).TrimEnd(PlaceHolderEndChracter);
            replacementValue = resourceManager.GetString(placeHolderValue, CultureInfo.CurrentCulture);

            var haveReplacableValue = !string.IsNullOrEmpty(replacementValue);
            return haveReplacableValue;
        }

        #endregion
    }

So now we can load the file and manipulate the contents, but we do not have anything to orchestrate these two processes, and how do we serve the modified file back to the client? Well we need a new controller; the `JavascriptFileController` with an "Action" called `CulturisedResourceFile()` which taking a "controller name" and a "view name" for teh view we need localised strings for as parameters. The "Action" first checks the parameters for null or emptyness and will return a BadRequest Http Status code for any errors. We then load the javascript file content, and pas this the class responsible for localising the placeholder text. If the javascript resource file was not found then a `HttpNotFoundResult` is returned, and if there is any error then a `HttpStatusCodeResult` carrying an "InternalServerError" `HttpStatusCode` is returned.

    public class JavascriptFileController : Controller
    {
        // GET: JavascriptResourceFile
        [HttpGet]
        //[OutputCache(Duration = Duration.InSeconds.OneHour, Location = OutputCacheLocation.Client, NoStore = true)]    // PROD ONLY
        //[OutputCache(Duration = Duration.InSeconds.TenSeconds, Location = OutputCacheLocation.Client, NoStore = true)] // TEST  ONLY
        [OutputCache(Duration = Duration.InSeconds.OneSecond, Location = OutputCacheLocation.Client, NoStore = true)]  // DEV  ONLY
        public ActionResult CulturisedResourceFile(string controllerName, string viewName)
        {
            if (string.IsNullOrWhiteSpace(controllerName)) return new HttpStatusCodeResult(HttpStatusCode.BadRequest, "controllerName not supplied");
            if (string.IsNullOrWhiteSpace(viewName)) return new HttpStatusCodeResult(HttpStatusCode.BadRequest, "viewName not supplied");

            const string baseScriptFolderPath = @"\Scripts";
            try
            {
                var originalFileContent = new JavascriptResourceFileContentLoader(
                    baseScriptFolderPath: baseScriptFolderPath,
                    controllerName: controllerName,
                    viewName: viewName)
                    .Load()
                    .Output;

                var culturisedFileContent = new JavascriptResourceFileContentCulturiser(
                    content: originalFileContent,
                    controllerName: controllerName,
                    viewName: viewName)
                    .Culturise()
                    .Output;

                return JavaScript(culturisedFileContent);
            }
            catch (FileNotFoundException)
            {
                return new HttpNotFoundResult("The requested resource was not found on the server. ");
            }
            catch (Exception)
            {
                return new HttpStatusCodeResult(HttpStatusCode.InternalServerError, "The requested resource causes an error on the server. ");
            }
        }
    }

We also set an `OutputCache` attribute on the action to save this code being run excesively as the file is VERY unlikley to change except during code enhancements. Rather than having an almost meaningless magic number indicating how many seconds the cache should work for, consider using well named constants in a nested static classes. For eaxample, add a "Constants" folder to the root of the web application, and within it add the following nested static constants classes. You may want to comment out the OutputCache attribute altogether while debugging, and set it with a low number during testing and ramp it up in production.

    public static class Duration
    {
        public static class InSeconds
        {
            public const int OneHour = 36000;
            public const int TenSeconds = 10;
            public const int OneSecond = 1;
        }
    }

If you need alternative durations elsewhere in your application, you can add to these classes and define well names classes and constants for them. For example you may want to override the default session timeout of 20 minutes using `Duration.InMinutes.HalfAnHour`, with a value of `30`. Or you may prefer the convention switched slightly to be `Duration.HalfAnHour.InSeconds`?


Now in the "Home/Index" view in the sripts section we can remove the original referece to the "~/Scripts/Home/app.home.index.resource.js" file and instead add a script tag and set the source to call to the `CulturisedResourceFile` action of the `JavascriptFileController` controller.

<script src="@Url.Action(" temp_src="@Url.Action("CulturisedResourceFile", "JavascriptFileController", new {Controller = "Home", View = "Index"})"></script>

Test the application both with the `globalization` node in teh web config setting "de-DE" or your default culture. You should see the message changes as you do. Remeber to turn the output cash off or set it very low! Once tested you can simplify the "app.home.index.js" file greatly to just use the js resource file.

if (typeof app === "undefined") {
    var app = {};
}
if (typeof app.home === "undefined") {
    app.home = {};
}
app.home.index = {
    promptUser: function () {
        alert(this.resources.message);
        alert(this.resources.message2);
    }
};

And this now requires the simplifcation of the view too.

@using Blogs.LocalisingJavascriptResourceFiles.UI.Resources.Home
@{
    ViewBag.Title = "Home Page";
}

<div class="jumbotron">
  <h1>ASP.NET</h1>
  <p class="lead">@Index.SubHeader</p>
</div>

@section Scripts{
  <script src="@Url.Content(" temp_src="@Url.Content("~/Scripts/Home/app.home.index.js")"></script>
  <script src="@Url.Action(" temp_src="@Url.Action("CulturisedResourceFile", "JavascriptFile", new {controllerName = "Home", viewName = "Index"})"></script>
  <script>
    app.home.index.promptUser();
  </script>
}

Summary

And there you have it; one way to localise your javascript messages in ASP.Net MVC. There are probably other (better?) solutions to get to the same end result, but I thought I'd share with you all my way.

Source code

The source code is available on my GitHub.

Saturday, 27 August 2016 22:14:44 (GMT Standard Time, UTC+00:00)  #    Comments [0] -
.Net | C# | CodeProject | JavaScript | Localisation | Localization | Resource Files
 Friday, 26 August 2016
This article follows on from Part 3 where we built the CommandStack leveraging EntityFramework and prepared to persist an order and some of its associated data to the database. In this article we will shift our focus to the the client, (well our Integration Tests!) and create a test that creates an order, persists it using the CommandStack and reads it back out with the QueryStack.

Since Part 2 I have renamed ReadModelTests to be OrderServiceTests as that now better represents what we are testing. We do need to make a tweak to the "dependency injection" mocker, the *Defaults* class before we can add any tests. Please bear in mind the Defaults class is just to new-up some of our objects. Normally i would use the Ninject DI framework for this purpose. 

    public static class Defaults
    {
        private readonly static string DefaultConnectionString = Properties.Settings.Default.DefaultConnection;

        private static ReadContext DefaultContext
        {
            get
            {
                return new ReadContext(DefaultConnectionString);
            }
        }

        public static OrderReadModel DefaultOrderReadModel
        {
            get
            {
                return new OrderReadModel(DefaultContext);
            }
        }

        public static OrderService DefaultOrderService
        {
            get
            {
                return new OrderService(DefaultOrderReadModel, DefaultUnitOfWork);
            }
        }

        public static UnitOfWork DefaultUnitOfWork
        {
            get
            {
                return new UnitOfWork(DefaultConnectionString);
            }
        }
    }
I'm not going to go into each of the tests I have written (however they are all in the source code on my GitHub repository. We will only focus on one test that will show off our Command Stack. We will create an command for the new order for an existing customer, and two of the products in the database. We will use the service to generated a new order Id and then create the CreateNewOrderForCustomerWithProductsCommand. (IDEA: This command maybe better named as `CreateNewOrderWithProductsForCustomerCommand`?). Once the command is created we will use a new `TransactionScope` so we can roll back the transaction and leave the database in the state we found it after each run of the test. Once inside the transaction we will use the OrderService to create the order. We will then use the OrderReadModel (from the second post in this series) to read the new order details back out so we may check all of the order details are correct once we have rolled back the transaction.
        [TestMethod]
        public void CreateNewOrderForCustomerWithProducts_WhenGivenValidProducts_CreatesAnOrder()
        {
            // ARRANGE
            var customerId = new Guid("17e3a22e-07e5-4ab2-8e62-1b15f9916909");
            var productsOnOrder = new List<int> { 8, 9 };
            const string customerOrderNumber = "00123";
            var orderService = Defaults.DefaultOrderService;
            var orderId = orderService.GenerateNewOrderId();
            var command = new CreateNewOrderForCustomerWithProductsCommand
            {
                OrderId = orderId,
                CustomerId = customerId,
                ProductsOnOrder = productsOnOrder,
                CustomerOrderNumber = customerOrderNumber
            };
            OrderDetailsModel actual;

            // ACT
            using (var transaction = new TransactionScope())
            {
                orderService.CreateNewOrderForCustomerWithProducts(command);

                actual = orderService.GetOrderForId(orderId);

                transaction.Dispose();
            }

            // ASSERT
            Assert.IsNotNull(actual);
            Assert.IsNotNull(actual.ProductsOnOrder);
            Assert.AreEqual(2, actual.ProductsOnOrder.Count);

            var actualProduct1 = actual.ProductsOnOrder.FirstOrDefault(p => p.ProductId == 8);
            Assert.IsNotNull(actualProduct1);
            Assert.AreEqual(14.99M, actualProduct1.PurchasePrice);

            var actualProduct2 = actual.ProductsOnOrder.FirstOrDefault(p => p.ProductId == 9);
            Assert.IsNotNull(actualProduct2);
            Assert.AreEqual(29.99M, actualProduct2.PurchasePrice);
        }


Summary

So there we have it. A small solution showing how you can leverage the *StoredProcedureFramework* and *EntityFramework* to achieve CQRS in a .Net application. All of the code is available in [this GitHub]() repository.

Part 1 Setting up the data
Part 2 Querying the database using the QueryStack
Part 3 Writing to the database using the CommandStack

Disclaimer


I am the author of the Stored Procedure Framework.

Friday, 26 August 2016 04:30:52 (GMT Standard Time, UTC+00:00)  #    Comments [0] -
.Net | C# | CodeProject | Command Stack | CQRS | Query Stack | SQL Server | Integration Tests
 Thursday, 25 August 2016
This article follows on from Part 2 where we built the QueryStack and queried an order and some of its associated data, in this article we will shift our focus to the Command Stack and we will leverage EntityFramework to do add a new order to the database.

Before we can get started we have to make a small amendment to the dbo.Product table structure. I had omitted the Price column.

CREATE TABLE [dbo].[Product] (
    [Id]               INT            IDENTITY (1, 1) NOT NULL,
    [Key]              NVARCHAR (128) NOT NULL,
    [Name]             NVARCHAR (255) NOT NULL,
    [Description]      NVARCHAR (MAX) NOT NULL,
    [CreatedTimestamp] DATETIME       NOT NULL,
    [Price] MONEY NOT NULL,
    CONSTRAINT [PK_Product] PRIMARY KEY CLUSTERED ([Id] ASC)
);
We will also need to re-seed this table too with the price data added.
SET IDENTITY_INSERT [dbo].[Product] ON
INSERT INTO [dbo].[Product] ([Id], [Key], [Name], [Description], [CreatedTimestamp], [Price])
    VALUES (2, N'compressor-mac-2hp', N'2HP MAC Tools Compressor', N'Super dandy 2HP  portable compressor by MAC Tools ', N'2015-11-23 16:00:23', 450.00)
INSERT INTO [dbo].[Product] ([Id], [Key], [Name], [Description], [CreatedTimestamp], [Price])
    VALUES (5, N'snapon-ratchet-ring-metric-10-21', N'Snap-On Metric Ratchet Ring Set 10-21mm', N'Snap-On Metric Ratchet set 10mm - 21mm', N'2015-11-24 00:00:00', 180.00)
INSERT INTO [dbo].[Product] ([Id], [Key], [Name], [Description], [CreatedTimestamp], [Price])
    VALUES (7, N'snap-on-ratchet-screwdriver-red', N'Snap-On Ratchet Screwdriver in Red', N'Snap-On Ratchet Screwdriver in Red with six bits included', N'2015-11-24 01:01:24', 85.00)
INSERT INTO [dbo].[Product] ([Id], [Key], [Name], [Description], [CreatedTimestamp], [Price])
    VALUES (8, N'usmash-4lb-hammer', N'U-Smash 4lb lump hammer', N'U-Smash 4lb lump hammer', N'2015-11-25 16:00:35', 14.99)
INSERT INTO [dbo].[Product] ([Id], [Key], [Name], [Description], [CreatedTimestamp], [Price])
    VALUES (9, N'pry-master-prybar', N'Pri-Master 24" Pry-Bar', N'Pri-Master 24" Pry-Bar with plastic ergonmoic handle', N'2015-11-26 17:00:02', 29.99)
INSERT INTO [dbo].[Product] ([Id], [Key], [Name], [Description], [CreatedTimestamp], [Price])
    VALUES (10, N'snap-on-6-inch-slip-plyers', N'Snap-On 6 Inch Slip Plyers', N'Snap-On 6 Inch Slip Plyers, ideal for removing brake spring clips', N'2015-12-02 09:33:22', 45.99)
SET IDENTITY_INSERT [dbo].[Product] OFF
So now that is out of the way we can move on to the Blogs.EfAndSprocfForCqrs.DomainModel project, as we intend to use the Entity Framework for data access in the CommandStack lets use NuGet to add the Entity Framework library to this project. You can use the Package Manager in Visual Studio or the console. I prefer to use the GUI in Visual studio but if you prefer to use the console then the command line is  below.

    PM> Install-Package EntityFramework
  
The next task is to set up the DomainModel folder structure in the project.

    |--04.CommandStack
    |  +--Blogs.EfAndSprocfForCqrs.DomainModel
    |     +--Context
    |     |  +--Configuration
    |     +--Entities
    |     +--Factories
    |     +--Repositories
    |     +--Transactional
    |

Lets start in the Context folder and create the CommandContext. This will Inherit from EntityFramework's DbContext. It will have a constructor that will take a connection name or connection string and it will pass this on to the base class. We will switch off lazy loading as we don't need to worry about performance for this article. We will also disable the database initializer as we already have a perfectly good database to use.

    public class CommandContext : DbContext
    {
        // Uncomment parameterless constructor if you want to use the 'Entity Framework Power Tools' EDMX viewer
        //public CommandContext() {}

        public CommandContext(string nameOrConnectionString)
            : base(nameOrConnectionString)
        {
            Configuration.LazyLoadingEnabled = false;

            DisableDatabaseInitializer();
        }

        private static void DisableDatabaseInitializer()
        {
            Database.SetInitializer<CommandContext>(null);
        }
We will need four DbSets of entities, Customer, Order, Product and ProductOnOrder. We haven't created the entities yet, but will get on to them in a short while.
        public DbSet<Customer> Customer { get; set; }
        public DbSet<Order> Order { get; set; }
        public DbSet<Product> Product { get; set; }
        public DbSet<ProductOnOrder> ProductOnOrder { get; set; }
We need to override the OnModelCreating method to remove the pluralising convention and to apply all EntityTypeConfiguration classes to the DbModelbuilder. I used to manually instantiate every EntityTypeConfiguration class and this would nearly always catch me out as I'd forget to plumb new ones in. However courtesy of an answer by octavioccl on stack overflow I now have a more generic "catch-all" version which scans the assembly for all EntityTypeConfiguration.
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            RemoveConventions(modelBuilder);
            AddAllEntityConfigurations(modelBuilder);
        }

        private static void RemoveConventions(DbModelBuilder modelBuilder)
        {
            modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
        }

        /// <summary>
        /// Adds all entity configurations.
        /// </summary>
        /// <remarks>
        /// Courtesy of: octavioccl on Stack overflow, here: http://stackoverflow.com/a/27748465/254215
        /// </remarks>
        private void AddAllEntityConfigurations(DbModelBuilder modelBuilder)
        {
            var configurationsToRegister = GetAllEntityConfigurationsToRegister();

            RegisterEntityTypeConfigurations(modelBuilder, configurationsToRegister);

            base.OnModelCreating(modelBuilder);
        }

        private static void RegisterEntityTypeConfigurations(DbModelBuilder modelBuilder, IEnumerable<Type> configurationsToRegister)
        {
            foreach (var type in configurationsToRegister)
            {
                dynamic configurationInstance = Activator.CreateInstance(type);
                modelBuilder.Configurations.Add(configurationInstance);
            }
        }

        private static IEnumerable<Type> GetAllEntityConfigurationsToRegister()
        {
            var entityConfigurationsToRegister = Assembly.GetExecutingAssembly().GetTypes()
                .Where(type => !String.IsNullOrEmpty(type.Namespace))
                .Where(type => type.BaseType != null
                               && type.BaseType.IsGenericType
                               && type.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>));

            return entityConfigurationsToRegister;
        }
The next step is to head over to the Entities folder and create the actual entities we need. First we will create the Customer Entity. As well as some basic properties we also have list of orders which is accessed by a ReadOnlyCollection. We are not doing much with this collection for this article, but we do need the collection for our EF configuration later.

    public class Customer
    {
        private readonly List<Order> _orders;

        public Guid Id { get; set; }
        public string Name { get; set; }
        public DateTime RegisteredDate { get; set; }
        public bool Active { get; set; }

        public virtual ReadOnlyCollection<Order> Orders
        {
            get { return _orders.AsReadOnly(); }
        }
    }
Now to create the Order Entity. This entity also has some basic properties. It also has a ReadOnlyCollection of products which are on the order. It is backed by a private list which can only be added to with the AddProductsToOrder method. We also have a property of type Customer which is the owner of the order and our navigation property, and along side this (for convenience) we will also hold the Customer Id as a foreign key property. IF this seems a bit awkward / or an overkill see great Pluralsight course on using EntityFramework by Julie Lerman. In the course she highlights why having the foreign key makes your life easier even if it does "muddy" your entity model a little. This link also mentions the benefits of using foreign keys. Anyway, its down to personal preference, I put them in, you can choose not to.
    public class Order
    {
        private readonly List<ProductOnOrder> _productsOnOrder;

        public Order()
        {
            _productsOnOrder = new List<ProductOnOrder>();
        }

        public Guid Id { get; set; }
        public string CustomerOrderNumber { get; set; }
        public DateTime CreatedOnTimeStamp { get; set; }
        public virtual ReadOnlyCollection<ProductOnOrder> ProductsOnOrder {
            get { return _productsOnOrder.AsReadOnly(); }
        }

        public Guid CustomerId { get; set; }
        public virtual Customer OrderOwner { get; set; }

        public void AddProductsToOrder(List<ProductOnOrder> productsOnOrder)
        {
            if(productsOnOrder == null) throw new ArgumentNullException("productsOnOrder");
            if(productsOnOrder.Count == 0) return;

            _productsOnOrder.AddRange(productsOnOrder);
        }
    }
The Product entity is straight forward.
    public class Product
    {
        public int Id { get; set; }
        public string Key { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }
        public DateTime CreatedTimestamp { get; set; }
        public decimal Price { get; set; }
    }
As is the ProductOnOrder entity, although this does have a navigation property which is a reference to the parent Order object.
    public class ProductOnOrder
    {
        public int Id { get; set; }
        public Guid OrderId { get; set; }
        public int ProductId { get; set; }
        public decimal PurchasePrice { get; set; }

        public virtual Order Order { get; set; }
    }
Now we need to quickly flip back into the Configuration folder inside the Context folder to add in all of the EntityTypeConfiguration classes. The CustomerConfiguration just defines the primary key.
    public class CustomerConfiguration : EntityTypeConfiguration<Customer>
    {
        public CustomerConfiguration()
        {
            HasKey(customer => customer.Id);
        }
    }
The OrderConfiguration defines the primary key and also the one to many Customer to Order relationship using the fluent API.

    public class OrderConfiguration : EntityTypeConfiguration<Order>
    {
        public OrderConfiguration()
        {
            HasKey(order => order.Id);
            HasRequired(order => order.OrderOwner)
                .WithMany(customer => customer.Orders)
                .HasForeignKey(order => order.CustomerId);
        }
    }
The ProductConfiguration is simple again with just the primary key defined.
    public class ProductConfiguration : EntityTypeConfiguration<Product>
    {
        public ProductConfiguration()
        {
            HasKey(product => product.Id);
        }
    }
And lastly the ProductOnOrderConfiguration has the primary key and the one to many relationship for the Order to the products on the order.
    public class ProductOnOrderConfiguration : EntityTypeConfiguration<ProductOnOrder>
    {
        public ProductOnOrderConfiguration()
        {
            ToTable("ProductOrdered");
            HasKey(productOnOrder => productOnOrder.Id);
            HasRequired(productOnOrder => productOnOrder.Order)
                .WithMany(order => order.ProductsOnOrder)
                .HasForeignKey(productOnOrder => productOnOrder.OrderId);
        }
    }
Lets now move to the Factories folder and add an OrderFactory class whose purpose will be to construct an order for us. When we create a new order we will need a unique identifier for it. For simplicity in this article I have chosen to use Guids so we will need a method in the factory that will return a new Guid. I know that using non-sequenctial Guids in a large database table can cause a performance concern so some people tend to shy away from them. Some people may prefer to use a Long Integer with a high-low strategy for generation, but for a web application where the Order ID may be passed in a query string or as a route parameter a non-guessable ID seems a more preferable idea for customer and order identifiers to me. So for the purpose of this article, Guids it is!

    public static class OrderFactory
    {
        public static Guid CreateNewOrderId()
        {
            return Guid.NewGuid();
        }
We also need a way of building a list of ProductOnOrder which the order will carry for the order from a list of Product objects which the customer selected. The method basically iterates through the list of products creating new ProductOnOrder objects with them and the specified order id.
        public static List<ProductOnOrder> CreateProductsOnOrder(Guid orderId, List<Product> productsOnOrder)
        {
            if (productsOnOrder == null) throw new ArgumentNullException("productsOnOrder");

            var result = new List<ProductOnOrder>();
            if (!productsOnOrder.Any()) return result;

            foreach (var product in productsOnOrder)
            {
                var productOnOrder = new ProductOnOrder
                {
                    ProductId = product.Id,
                    OrderId = orderId,
                    PurchasePrice = product.Price
                };
                result.Add(productOnOrder);
            }

            return result;
        }
The last method in the factory creates an actual Order object it self, using an order id, customer id, a customer order number if supplied and of course a list of products to add to the order.
        public static Order CreateOrderFrom(Guid orderId, Guid customerId, string customerOrderNo, List<ProductOnOrder> productsOnOrder)
        {
            if (orderId == Guid.Empty) throw new ArgumentOutOfRangeException("orderId", "Order Id must not be empty");
            if (customerId == Guid.Empty) throw new ArgumentOutOfRangeException("customerId", "Customer Id must not be empty");
            if (productsOnOrder == null) throw new ArgumentNullException("productsOnOrder");
            if (!productsOnOrder.Any()) throw new ArgumentOutOfRangeException("productsOnOrder", "An order must have products on it. ");

            var order = new Order
            {
                Id = orderId,
                CustomerId = customerId,
                CustomerOrderNumber = customerOrderNo,
                CreatedOnTimeStamp = DateTime.Now
            };
            order.AddProductsToOrder(productsOnOrder);
            return order;
        }
Ideally I should create a suite of unit tests for the functions in the OrderFactory, but it is not the scope of this article to go into the pros and cons of unit testing.

Next up we need to focus on the repositories, so lets open the Repositories folder and lets start by creating a repository for the Order, the OrderRepository. The repository for the orders is relatively simple and straight forward. We could have methods like `Order Get(Guid id)` or `IEnumerable<Order> GetAllForCustomer(Guid customerId)` within the repository but for the purposes of this article we just need an `void Add(Order order)` method. The repository must first of all be constructed with our CommandContext.

    public class OrderRepository
    {
        private readonly CommandContext _context;

        public OrderRepository(CommandContext context)
        {
            if (context == null) throw new ArgumentNullException("context");

            _context = context;
        }

        public void Add(Order order)
        {
            if (order == null) throw new ArgumentNullException("order");

            _context.Set<Order>().Add(order);
        }
    }


We will also need a repository for the products as when we create an order we need some additional product information, for example the price at the time of ordering. So the ProductRepository will have a single method `IEnumerable<Product> GetProductsForIds(List<int> idList)` and like the order repository it will be constructed with our CommandContext.
    public class ProductRepository
    {
        private readonly CommandContext _context;

        public ProductRepository(CommandContext context)
        {
            if (context == null) throw new ArgumentNullException("context");

            _context = context;
        }

        public IEnumerable<Product> GetProductsForIds(List<int> idList)
        {
            return _context.Set<Product>()
                .Where(product => idList.Contains(product.Id));
        }
    }
As we will be updating two tables in the database when we create an order, one to hold the order and one to hold the products on the order we need to ensure that our updating is carried out in a single atomic action. For this we will use the UnitOfWork pattern. So lets move to the Transactional folder and create our UnitOfWork. As the unit of work will hold it's own instance of the CommandContext and will need to ensure it disposes of this correctly it will need to implement the IDisposable interface.
    public class UnitOfWork : IDisposable
    {
        private bool _disposed;
        private readonly CommandContext _context;
We will construct the UnitOfWork with a connection name or connection string, and use this to instantiate a CommandContext. This will live around for the life of the UnitOfWork and be disposed along with the UnitOfWork by following the Dispose Pattern. The UnitOfWork will contain two repositories, an OrderRepository and a ProductsRepository. These will both be instantiated with the CommandContext instance.
        public UnitOfWork(string nameOrConnectionString)
        {
            if (string.IsNullOrWhiteSpace(nameOrConnectionString)) throw new ArgumentNullException("nameOrConnectionString");

            _context = new CommandContext(nameOrConnectionString);

            Orders = new OrderRepository(_context);
            Products = new ProductRepository(_context);
        }
As well as the properties to expose the repositories there is a single method `Complete()` which will call `SaveChanges()` on the CommandContext. This method is called when all updates made to the repositories need to be persisted back to the database.
        /// <summary>
        /// Called to complete a unit of work.
        /// </summary>
        public void Complete()
        {
            _context.SaveChanges();
        }
Now the UnitOfWork is complete, we can focus on the Blogs.EfAndSprocfForCqrs.Services project and open the OrderService and use what we have created so far in this post to add a new order to the database. First we will add another private field to the service and this will hold a reference to the UnitOfWork. we will initialize it from the constructor just like we do with the OrderReadModel. we will pass the UnitOfWork into the service as we may want many services to perform actions all in one atomic transaction. for this reason we will not dispose of the UnitOfWork when the service dies, we will let the constructing code handle disposing of the UnitOfWork for us.
        private readonly OrderReadModel _orderReadModel;
        private readonly UnitOfWork _unitOfWork;

        public OrderService(OrderReadModel orderReadModel, UnitOfWork unitOfWork)
        {
            if (orderReadModel == null) throw new ArgumentNullException("orderReadModel");
            if (unitOfWork == null) throw new ArgumentNullException("unitOfWork");

            _orderReadModel = orderReadModel;
            _unitOfWork = unitOfWork;
        }
Now we need to add a new method to the service to create the new order for the customer along with the products they have ordered. We will use a command object to carry the information we need from the client to create the order. So lets add a Commands folder in the Services project and within it create a CreateNewOrderForCustomerWithProductsCommand command. We actually don't need much data from the client, all we need is the OrderId, the CustomerId, the customer's order number, and a list  containing the product IDs for the products on order. (In a real world scenario we'd probably want to hold the quantities of the product as well, but if I am honest, I simply forgot!)
    public class CreateNewOrderForCustomerWithProductsCommand
    {
        public Guid OrderId { get; set; }
        public Guid CustomerId { get; set; }
        public List<int> ProductsOnOrder { get; set; }
        public string CustomerOrderNumber { get; set; }
    }
Now we have a command to carry out order information, we can create the service method to create the order passing the command as the Parameter. The method will have a few guard clauses to try and ensure we cannot pass a command with an invalid state to the method. We then use the list of product Ids to get a list of products from the database. We check if we got less products back than the ids passed in and throw an exception if we do.

Providing we got an equal quantity of products back we will use the order factory to create a list of ProductOnOrder items. We will then pass this along with the Order Id, Customer Id and Customer Order Number to the OrderFactory to create an new Order. This will be added to the OrderRepository via the UnitOfWork and then we will complete the transaction.
        /// <exception cref="System.ArgumentNullException">command</exception>
        /// <exception cref="System.ArgumentException">
        /// command.CustomerId
        /// or
        /// command.ProductsOnOrder
        /// </exception>
        public void CreateNewOrderForCustomerWithProducts(CreateNewOrderForCustomerWithProductsCommand command)
        {
            if (command == null) throw new ArgumentNullException("command");
            if (command.OrderId == Guid.Empty) throw new ArgumentOutOfRangeException("command.OrderId", "OrderId must not be empty");
            if (command.CustomerId == Guid.Empty) throw new ArgumentOutOfRangeException("command.CustomerId", "CustomerId must not be empty");
            if (command.ProductsOnOrder == null) throw new ArgumentException("command.ProductsOnOrder");
            if (command.ProductsOnOrder.Count == 0) throw new ArgumentOutOfRangeException("command.ProductsOnOrder", "ProductsOnOrder must not be empty");

            var productsOrdered = _unitOfWork.Products.GetProductsForIds(command.ProductsOnOrder).ToList();
            var productCountShortfall = command.ProductsOnOrder.Count - productsOrdered.Count;
            if (productCountShortfall > 0) throw new InvalidOperationException(productCountShortfall + " products on order not found! ");

            var productsOnOrder = OrderFactory.CreateProductsOnOrder(command.OrderId, productsOrdered);
            var order = OrderFactory.CreateOrderFrom(command.OrderId, command.CustomerId, command.CustomerOrderNumber, productsOnOrder);

            _unitOfWork.Orders.Add(order);
            _unitOfWork.Complete();
        }
While we are in the service we will provide a method for generating new valid OrderIds. In our case we wil just let the OrderFactory create a new Guid, but we may have had to go to the database to get the next sequential Guid, or the next available *Long Integer* using a *High-Low* strategy.

In Part 4 we move to the client, (well our Integration Tests!) and

Part 1 Setting up the data
Part 2 Querying the database using the QueryStack

Disclaimer

I am the author of the Stored Procedure Framework.


Thursday, 25 August 2016 20:54:18 (GMT Standard Time, UTC+00:00)  #    Comments [0] -
.Net | C# | CodeProject | Command Stack | CQRS | Entity Framework | Integration Tests | SQL Server | Stored Procedure Framework
 Monday, 08 August 2016

Using Entity Framework and the Store Procedure Framework To Achieve CQRS - Part #2

This article follows on from Part 1 where we described the background to the problem, set up the solution and added seed data to the database. In this article we will tackle the QueryStack and more specifically the ReadModel.

So moving on to the "Blogs.EfAndSprocfForCqrs.ReadModel" project, as we intend to use the Stored Procedure Framework for data access in the QueryStack lets use NuGet to add the Stored Procedure Framework library to this project. At the time of writing version 1.0.3. is available on NuGet so this is the version I will add to the project. You can use the Package Manager in Visual Studio or the console. I prefer to use the GUI in Visual studio but if you prefer to use the console then the command line is below.

PM> Install-Package Dibware.StoredProcedureFramework

The next task is to set up the ReadModel folder structure in the project.

    |--03.QueryStack 
    | +--Blogs.EfAndSprocfForCqrs.ReadModel
    | +--Context
    | +--Dtos
    | +--ReadModels
    | +--StoredProcedures
    |

In the Context folder create a new public class called ReadContext. Give it a private field of type SqlConnection and make it implement the Dispose Pattern, closing and disposing of the connection within The disposing path of the Dispose(bool disposing) method. This will ensure that when our ReadContext is disposed our connection is closed and cleaned up.

public class ReadContext : IDisposable
{
    private bool _disposed;

    private SqlConnection _connection;

    public ReadContext(string connectionString)
    {
        Guard.ArgumentIsNotNullOrEmpty(connectionString, "connectionString");

        _connection = new SqlConnection(connectionString);
    }

    internal SqlConnection Connection
    {
        get { return _connection; }
    }

    public void Dispose()
    {
        Dispose(true);
    }

    ~ReadContext()
    {
        Dispose(false);
        GC.SuppressFinalize(this);
    }

    private void Dispose(bool disposing)
    {
        if (_disposed) return;

        if (disposing) CloseAndDisposeConnection();


        _disposed = true;
    }

    private void CloseAndDisposeConnection()
    {
        if (_connection == null) return;

        if (_connection.State != ConnectionState.Closed) _connection.Close();

        if (_connection != null)
        {
            _connection.Dispose();
            _connection = null;
        }
    }
}

So we have a class to handle our database connection, and next we need a class to represent the "GetOrderDetailsForOrderId" stored procedure which we will be calling to get our order, and it's closely associated data. It may seem a bit of an overkill as the ReadContext does little more than pass through to the SqlConnection it holds. I have chosen this approach for one key reason, when we do the command model there will be a reflection in the objects created, so it will better help analysis of teh similarities and differences between using EF and SprocF.

In addition it is my intention a future release of the Stored Procedure Framework to add a base context class which will be similar to EntityFramework's DBConext, so the API will be similar to how a developer uses EF. At present this will require a breaking change so will not likely be implemented in the Stored Procedure Framework until version 2.0 where it will be more acceptable to introduce a breaking change to the API.

In the StoredProcedures folder create a new internally scoped class called GetOrderDetailsForOrderId which inherits fromStoredProcedureBase with TReturn being a generic List of OrderDto objects and with the TParamet being of typeGetOrderDetailsForOrderId.Parameter, both yet to be defined.

internal class GetOrderDetailsForOrderId
    : StoredProcedureBase<GetOrderDetailsForOrderId.ResultSet, GetOrderDetailsForOrderId.Parameter>
{
}

Create a nested Parameter class within the stored procedure class with a single property called "Id" of type System.Guid and with public getter and setter accessors.

    internal class Parameter
    {
        public Guid Id { get; set; }
    }

Create a nested ResultSet class within the stored procedure class with three public properties which are lists of Dtos which represent the three RecordSets that will be returned from the stored procedure. Ensure these properties are instantiated in the class's constructor.

    internal class ResultSet
    {
        public ResultSet()
        {
            Orders = new List<OrderDto>();
            Customers = new List<CustomerDto>();
            ProductsOrdered = new List<ProductsOrderedDto>();
        }

        public List<OrderDto> Orders { get; set; }
        public List<CustomerDto> Customers { get; set; }
        public List<ProductsOrderedDto> ProductsOrdered { get; set; }
    }

We also need a constructor which tales the parameters and passes them on to the base class.

    public GetOrderDetailsForOrderId(GetOrderDetailsForOrderId.Parameter parameters)
        :base(parameters)
    { }

The finished stored procedure class should look like below.

internal class GetOrderDetailsForOrderId
    : StoredProcedureBase<GetOrderDetailsForOrderId.ResultSet, GetOrderDetailsForOrderId.Parameter>
{
    public GetOrderDetailsForOrderId(GetOrderDetailsForOrderId.Parameter parameters)
        :base(parameters)
    {

    }

    internal class Parameter
    {
        public Guid OrderId { get; set; }
    }

    internal class ResultSet
    {
        public List<OrderDto> Orders { get; set; }
        public List<CustomerDto> Customers { get; set; }
        public List<ProductsOrderedDto> ProductsOrdered { get; set; }
    }
}

Now we need some public DTO classes too represent the rows being returned from the stored procedure. Lets start with theOrderDto which represents the rows from the first Recordset in the stored procedure.

public class OrderDto
{
    public Guid Id { get; set; }
    public Guid CustomerId { get; set; }
    public string CustomerOrderNumber { get; set; }
    public DateTime CreatedOnTimeStamp { get; set; }
}

The second Recordset contains the customer information so lets create a CustomerDto DTO to represent that.

public class CustomerDto
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public DateTime RegisteredDate { get; set; }
    public bool Active { get; set; }
}

And lastly we need a DTO to represent the products on the order, the ProductsOrderedDto.

public class ProductsOrderedDto
{
    public int Id { get; set; }
    public int ProductId { get; set; }
    public string Key { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public decimal PurchasePrice { get; set; }
}

So these DTOs will represents the rows returned from the stored procedure, but it would be nice to wrap these into a single object to return to the client. For this we will have an OrderDetailsDto. This will include some of the properties of the OrderDtoand will have an "Id", a "CustomerOrderNumber" and a "CreatedOnTimeStamp" property. It will also encapsulate theCustomerDto and contain a list of ProductsOrdered.

public class OrderDetailsDto
{
    public OrderDetailsDto()
    {
        ProductsOnOrder = new List<ProductsOrderedDto>();
    }

    public Guid Id { get; set; }
    public string CustomerOrderNumber { get; set; }
    public DateTime CreatedOnTimeStamp { get; set; }

    public CustomerDto OrderOwner { get; set; }
    public List<ProductsOrderedDto> ProductsOnOrder { get; private set; }
}

Next in the ReadModels folder create a new public class called OrderReadModel which will use the "GetOrderDetailsForOrderId" class along with the Stored Procedure Framework to pull data from the database and load the DTOs with data. We know we will return an OrderDetailsDto do we could just make this the return type like so...

public OrderDetailsDto GetOrderDetails(Guid id)
{
    throw new NotImplementedException();
}

This method signature indicates that it will return an instance of an OrderDetailsDto. However if an id for a order that does not exist in the database is passed then the method result will be NULL. This results in any calling code having to ask if the result is NULL before acting upon the result. I'm not a big fan of this so what I propose is we return a wrapper object that will either contain a result or not, but the wrapper object itself will ALWAYS be an instance. So what we need is a wrapper that indicates ONE or ZERO results were found. for this we can use the following generic class.

public class SingleSearchResult<T> : IEnumerable<T>
{
    private readonly T _result;

    public SingleSearchResult()
    {
        _result = default(T);
    }

    public SingleSearchResult(T result)
    {
        if (result == null) throw new ArgumentNullException("result");

        _result = result;
    }

    public IEnumerator<T> GetEnumerator()
    {
        if (ResultWasFound)
        {
            yield return _result;
        }
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    /// <summary>
    /// Gets a value indicating whether a result was found.
    /// </summary>
    /// <value>
    ///   <c>true</c> if a result was found; otherwise, <c>false</c>.
    /// </value>
    public bool ResultWasFound
    {
        get { return _result != null; }
    }

    /// <summary>
    /// Gets the result (providing one was found); otherwise and exception is thrown.
    /// </summary>
    /// <value>
    /// The result.
    /// </value>
    /// <exception cref="System.InvalidOperationException">
    /// No result was present. Please use 'ResultWasFound' property 
    /// to check for result before calling the 'Result' function.
    /// </exception>
    public T Result
    {
        get
        {
            if (ResultWasFound) return _result;

            throw new InvalidOperationException(
                "No result was present. Please use 'ResultWasFound' property " + 
                "to check for result before calling the 'Result' function. ");
        }
    }
}

The class expects a type parameter, which will identify the type we want the SingleSearchResult to hold. The class can either be constructed with a single instance of this type or with nothing. If with an instance was passed in then the ResultWasFoundproperty will return true and the Result function can be called to retrieve the result. If the parameterless constructor was called then the ResultWasFound property will return false, and if the Result function called an exception will be thrown. The class also implements the IEnumerable interface so can be enumerated through once if a result was found.

Now we have the SingleSearchResult we can change our method signature to indicate to the caller what the results of the method call will be in a clearer manner.

    public SingleSearchResult<OrderDetailsDto> GetOrderDetails(Guid id)
    {
        throw new NotImplementedException();
    }

Before we create the implementation we need to pass in the ReadContext into the ReadModel.

public class OrderReadModel
{
    private readonly ReadContext _readContext;

    public OrderReadModel(ReadContext readContext)
    {
        Guard.ArgumentIsNotNull(readContext, "readContext");

        _readContext = readContext;
    }

Now we have a way to access the database, lets get on and create the implementation. First we need to create an instance of the stored procedures parameters and then the stored procedure its self. We can then call the procedure through the ReadContext and hold onto the results.

    public SingleSearchResult<OrderDetailsDto> GetOrderDetails(Guid id)
    {
        var parameters = new GetOrderDetailsForOrderId.Parameter { OrderId = id };
        var procedure = new GetOrderDetailsForOrderId(parameters);

        GetOrderDetailsForOrderId.ResultSet procedureResult = _readContext.Connection.ExecuteStoredProcedure(procedure);

If we did not return an order then we need to just return an empty SingleSearchResult.

        if (!procedureResult.Orders.Any()) return new SingleSearchResult<OrderDetailsDto>();

Otherwise we can get on and process the results. We get the first order and use that to populate the properties of ourOrderDetailsDto. We then add the customer as the OrderOwner and finally the products which were on the order.

        var firstOrder = procedureResult.Orders.First();
        var result = new OrderDetailsDto
        {
            CreatedOnTimeStamp = firstOrder.CreatedOnTimeStamp,
            CustomerOrderNumber = firstOrder.CustomerOrderNumber,
            Id = firstOrder.Id,
            OrderOwner =  procedureResult.Customers.FirstOrDefault()
        };
        result.ProductsOnOrder.AddRange(procedureResult.ProductsOrdered);

And then return a SingleSearchResult with a OrderDetailsDto contained within it.

        return new SingleSearchResult<OrderDetailsDto>(result);

We are now ready to call this code, so lets go to the services project Blogs.EfAndSprocfForCqrs.Services and add a class calledOrderService. This service will provide all of the orchestration for the client between the ReadModel and WriteModel giving a single "endpoint" (I use this term loosely) for the client to connect to. The Blogs.EfAndSprocfForCqrs.Services will need a reference to the Blogs.EfAndSprocfForCqrs.ReadModel project and then we can add field to hold a reference to theOrderReadModel in the OrderService class.

public class OrderService
{
    private readonly OrderReadModel _orderReadModel;

    public OrderService(OrderReadModel orderReadModel)
    {
        if (orderReadModel == null) throw new ArgumentNullException("orderReadModel");

        _orderReadModel = orderReadModel;
    }
}

Lets now create a function to return the order details to the client. The function will return an OrderDetailsModel (which we have not yet defined) and will query the OrderReadModel to get the data for this. Once a response has returned from theOrderReadModel we will check if a result was found and if it was not we will throw an exception. This may unnecessarily seem "harsh" but in theory this method should never be called without a valid Order Id. If it is then it is either due to a bug in the calling code or an attempt to access data that should not. If we have a result then we can go ahead and construct theOrderDetailsModel from the OrderDetailsDto. We have chosen not to just expose the OrderDetailsDto straight to the client for two reasons. The first is to do this we would either have to let the client have a reference to theBlogs.EfAndSprocfForCqrs.ReadModel so it can see the OrderDetailsDto or we would have to declare the OrderDetailsDto in ashared project that multiple layers can see, which is not something I am adverse to but just choose not to in this case due to the second reason. The second reason is that this service method may also do some additional orchestration and data gathering which may need to be appended to the object being returned. If we use the DTO then the DTO has to have extra properties which were not needed to be populated by the OrderReadmodel in the first call. It may seem like unnecessary duplication of code, but I feel each layer and each class in each layer should only be interested in what it needs to know. So Lets populate define and populate the OrderDetialsModel

public class OrderDetailsModel
{
    public Guid Id { get; private set; }
    public string CustomerOrderNumber { get; private set; }
    public DateTime CreatedOnTimeStamp { get; private set; }
    public CustomerModel OrderOwner { get; private set; }
    public List<ProductModel> ProductsOnOrder { get; private set; }

    public OrderDetailsModel(OrderDetailsDto orderDetails)
    {
        if (orderDetails == null) throw new ArgumentNullException("orderDetails");

        ProductsOnOrder = new List<ProductModel>();

        CreatedOnTimeStamp = orderDetails.CreatedOnTimeStamp;
        CustomerOrderNumber = orderDetails.CustomerOrderNumber;
        OrderOwner = new CustomerModel(orderDetails.OrderOwner);
        Id = orderDetails.Id;
        LoadProductsOnOrder(orderDetails.ProductsOnOrder);
    }

    private void LoadProductsOnOrder(List<ProductsOrderedDto> productsOnOrder)
    {
        foreach (var productsOrderedDto in productsOnOrder)
        {
            var productOnOrder = new ProductModel
            {
                Description = productsOrderedDto.Description,
                Id = productsOrderedDto.Id,
                Key = productsOrderedDto.Key,
                Name = productsOrderedDto.Name,
                ProductId = productsOrderedDto.ProductId,
                PurchasePrice = productsOrderedDto.PurchasePrice
            };

            ProductsOnOrder.Add(productOnOrder);
        }
    }
}

public class CustomerModel
{
    public CustomerModel(CustomerDto orderOwner)
    {
        Id = orderOwner.Id;
        Active = orderOwner.Active;
        Name = orderOwner.Name;
        RegisteredDate = orderOwner.RegisteredDate;
    }

    public Guid Id { get; private set; }
    public bool Active { get; private set; }
    public string Name { get; private set; }
    public DateTime RegisteredDate { get; private set; }
}

public class ProductModel
{
    public string Description { get; set; }
    public int Id { get; set; }
    public string Key { get; set; }
    public string Name { get; set; }
    public int ProductId { get; set; }
    public decimal PurchasePrice { get; set; }
}

That's it for the OrderService, now lets move to our Client...., well.. the Blogs.EfAndSprocfForCqrs.IntegrationTests project! We will start by adding adding a reference to the Blogs.EfAndSprocfForCqrs.Services project, adding a ReadModelTests class which will represent our calling client and within this creating a new test to represent a call to the service with an invalid OrderId. Within this test we will instantiate a new instance of the OrderService... but wait... we can't do this as the constructor requires an instance of an OrderReadModel which we just don't have a reference for! Damn. So normally I'd use a dependency injection framework like NInject to handle this, but for the sake of brevity lets just set a quick project calledBlogs.EfAndSprocfForCqrs.Dependencies in the 01.Client folder to handle all of our default dependencies. This project will need project references to Blogs.EfAndSprocfForCqrs.ReadModel and Blogs.EfAndSprocfForCqrs.Services and will contain a single static class.

public static class Defaults
{
    public readonly static string DefaultConnectionString = Properties.Settings.Default.DefaultConnection;

    public static ReadContext DefaultContext
    {
        get
        {
            return new ReadContext(DefaultConnectionString);
        }
    }

    public static OrderReadModel DefaultOrderReadModel
    {
        get
        {
            return new OrderReadModel(DefaultContext);
        }
    }

    public static OrderService DefaultOrderService
    {
        get
        {
            return new OrderService(DefaultOrderReadModel);
        }
    }
}

So NOW we can finally move to our "client" and create a test for retrieving data for an order with an ID that does not exists. Because one does not exist we would expect an InvalidOperationException to be raised.

[TestClass]
public class ReadModelTests
{
    [TestMethod]
    [ExpectedException(typeof(InvalidOperationException))]
    public void GetOrderForId_ThrowsException_WhenGivenInvalidId()
    {
        // ARRANGE
        var orderService = Dependencies.Defaults.DefaultOrderService;
        var invalidId = new Guid("0bab4fc6-d749-455c-afee-73cfb0a01d08");

        // ACT
        orderService.GetOrderForId(invalidId);
    }
}

Now lets add a test to simulate retrieving order details for an order whose ID does exist.

[TestMethod]
public void GetOrderForId_ReturnsOrderDetails_WhenGivenAValidId()
{
    // ARRANGE
    var orderService = Dependencies.Defaults.DefaultOrderService;
    var invalidId = new Guid("4a61a22a-bade-d780-bbfa-be19c7746d87");

    // ACT
    var model = orderService.GetOrderForId(invalidId);

    // ASSERT
    Assert.AreEqual("17e3a22e-07e5-4ab2-8e62-1b15f9916909", model.OrderOwner.Id.ToString());
    Assert.AreEqual("0000001", model.CustomerOrderNumber);
    Assert.AreEqual("2016/01/02 11:08:34", model.CreatedOnTimeStamp.ToString("yyyy/MM/dd HH:mm:ss", CultureInfo.InvariantCulture));
    Assert.IsTrue(model.OrderOwner.Active);
    Assert.AreEqual("17e3a22e-07e5-4ab2-8e62-1b15f9916909", model.OrderOwner.Id.ToString());
    Assert.AreEqual("Mike Finnegan", model.OrderOwner.Name);
    Assert.AreEqual("1961/01/19 00:00:00", model.OrderOwner.RegisteredDate.ToString("yyyy/MM/dd HH:mm:ss", CultureInfo.InvariantCulture));
    Assert.AreEqual(3, model.ProductsOnOrder.Count);
    Assert.AreEqual(1, model.ProductsOnOrder.First().Id);
    Assert.AreEqual(5, model.ProductsOnOrder.First().ProductId);
    Assert.AreEqual("snapon-ratchet-ring-metric-10-21", model.ProductsOnOrder.First().Key);
    Assert.AreEqual("Snap-On Metric Ratchet Ring Set 10-21mm", model.ProductsOnOrder.First().Name);
}

So now we have called our service for an order that does not exist and for one that does. This about wraps up this article. In the next article we will look at using Entity Framework for the Command Stack. If you wish to reread the part one, the link is below.

Links

Using Entity Framework and the Store Procedure Framework To Achieve CQRS - Part 1

Using Entity Framework and the Store Procedure Framework To Achieve CQRS - Part #3

This post and all corresponding code and data can be found on my GitHub project -https://github.com/dibley1973/Blogs.UsingEFAndSprocFToAcheiveCQRS

Disclaimer

I am the author of the Stored Procedure Framework.

Monday, 08 August 2016 19:23:34 (GMT Standard Time, UTC+00:00)  #    Comments [0] -
.Net | C# | CodeProject | Command Stack | CQRS | Entity Framework | Query Stack | ReadModel | Stored Procedure Framework | Stored Procedures
Categories
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Archive
<2016 December>
SunMonTueWedThuFriSat
27282930123
45678910
11121314151617
18192021222324
25262728293031
1234567
Blogroll
 DAVID HEINEMEIER HANSSON
Creator of ruby on Rails
 Harry Pierson
Passion * Technology * Ruthless Competence
 Joshua Flanagan
A .NET Software Developer
 Martin Ffowler
Author, speaker, and loud-mouth on the design of enterprise software
 Michael Schwarz's Blog
Developing applications on the Microsoft platform since Windows 3.1!
 Scot GU
Scott Guthrie lives in Seattle and builds a few products for Microsoft
 Scott Hanselman
Programming Life and the Zen of Computers
About the author/Disclaimer

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2016
Duane Wingett
Sign In
Statistics
Total Posts: 91
This Year: 13
This Month: 0
This Week: 0
Comments: 66
Themes
Pick a theme:
All Content © 2016, Duane Wingett
DasBlog theme 'Business' created by Christoph De Baene (delarou)