Archive for the ‘C# (C-Sharp)’ Category.

How to easily access a web.config AppSettings value with a Type and a default value?

I wanted to make it easier to get a value from AppSettings in the web.config (or the app.config if you aren’t doing web) while converting to the proper type and having a default value.

Here is the syntax I started with that I didn’t like at all.

public static int MaxRetryAttempts = (string.IsNullOrWhiteSpace(ConfigurationManager.AppSettings["SmptRetries"]))
    ? int.Parse(ConfigurationManager.AppSettings["SmptRetries"])
    : 3;

I decided I wanted to have the following syntax:

ConfigurationManager.AppSettings.Get<T>(string key, T defaultValue)

I found a blog post that got me started. His syntax was very close to what I wanted already. He didn’t have the default value and he wasn’t an extension method, but wow, was this a real help. I was unaware of TypeDescriptor.GetConverter and was going to basically roll my own with an massively ugly case statement. So I am very happy I found his post.

I created the following NameValueCollectionExtensions.cs file.

using System.Collections.Specialized;
using System.ComponentModel;

namespace Rhyous.Extensions
{
    public static class NameValueCollectionExtensions
    {
        public static T Get<T>(this NameValueCollection collection, string key, T defaultValue)
        {
            var value = collection[key];
            var converter = TypeDescriptor.GetConverter(typeof(T));
            if (string.IsNullOrWhiteSpace(value) || !converter.IsValid(value))
            {
                return defaultValue;
            }

            return (T)(converter.ConvertFromInvariantString(value));
        }
    }
}

Details

  1. ConfigurationManager.AppSettings is of Type System.Collections.Specialized.NameValueCollection. So my extension method must be for that type.
  2. I changed the author’s method to be an extension method using the “this” keyword.
  3. I changed from using ConfirationManager.AppSettings to use the first parameter, collection, defined by the “this” keyword.
  4. I added a parameter for a default value.
  5. I changed the method code to return the default value, instead of throwing an exception, if the setting in the web.config is missing or empty.

Usage

I have to retry sending emails. I want the SmtpRetries to be an int obtained from the web.config’s AppSettings and have a default value of 3.

public static int MaxRetryAttempts = ConfigurationManager.AppSettings.Get("SmptRetries", 3);

Unit Tests

I really only wrote unit tests for int conversion. I expect that is sufficient. But if you want to write tests for a double or a other type feel free.

using System;
using System.Collections.Specialized;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Rhyous.Extensions.Tests
{
    [TestClass]
    public class NameValueCollectionExtensionsTests
    {
        private const string Name = "Retries";

        [TestMethod]
        public void IntValueExistsTest()
        {
            // Arrange
            const int defaultMaxRetries = 2;
            const int value = 3;
            var collection = new NameValueCollection { { Name, value.ToString() } };

            // Act
            var actual = collection.Get(Name, defaultMaxRetries);

            // Assert
            Assert.AreEqual(value, actual, "Valid value should return the valid value.");
        }

        [TestMethod]
        public void IntValueDoesNotExistTest()
        {
            // Arrange
            const int defaultMaxRetries = 2;
            var collection = new NameValueCollection();

            // Act
            var actual = collection.Get(Name, defaultMaxRetries);

            // Assert
            Assert.AreEqual(defaultMaxRetries, actual, "Missing value returns default.");
        }

        [TestMethod]
        public void IntValueIsEmptyStringTest()
        {
            // Arrange
            const int defaultMaxRetries = 2;
            var collection = new NameValueCollection { { Name, string.Empty } };

            // Act
            var actual = collection.Get(Name, defaultMaxRetries);

            // Assert
            Assert.AreEqual(defaultMaxRetries, actual, "Empty string returns default.");
        }

        [TestMethod]
        public void IntValueIsWhiteSpaceStringTest()
        {
            // Arrange
            const int defaultMaxRetries = 2;
            var collection = new NameValueCollection { { Name, "  " } };

            // Act
            var actual = collection.Get(Name, defaultMaxRetries);

            // Assert
            Assert.AreEqual(defaultMaxRetries, actual, "Whitespace string returns default.");
        }

        [TestMethod]
        public void IntValueIsDoubleTest()
        {
            // Arrange
            const int defaultMaxRetries = 2;
            const double value = 3.5; 
            var collection = new NameValueCollection { { Name, value.ToString() } };

            // Act
            var actual = collection.Get(Name, defaultMaxRetries);

            // Assert
            Assert.AreEqual(defaultMaxRetries, actual, "Invalid value returns default.");
        }

        [TestMethod]
        public void IntValueIsCharsTest()
        {
            // Arrange
            const int defaultMaxRetries = 2;
            const string value = "abc";
            var collection = new NameValueCollection { { Name, value } };

            // Act
            var actual = collection.Get(Name, defaultMaxRetries);

            // Assert
            Assert.AreEqual(defaultMaxRetries, actual, "Invalid value returns default.");
        }
    }
}

Authentication Token Service for WCF Services (Part 6 – A JavaScript client)

Drum roll please . . . This is the moment you’ve all been waiting for. The JavaScript client has finally arrived. In the past articles we have taken control of Authentication in WCF. The token authentication service was designed specifically for ReST like WCF services to be used by modern web and mobile apps. For modern web, that means the Basic Token Service for WCF Services has to work with JavaScript! Of course, it does. That is what it was designed for.

As for the WCF Services, I made a few improvements and fixed some bugs. I am not going to go over those changes. Just know it is a better example than what was delivered in part 6, but not much different.

Download this project here: WCF BTS JS Client

OK. So here is my little html and javascript example. I created a single html file, mostly. I added jquery and knockoutjs from NuGet. The rest is all in the TestPage/Index.html. Really, all you need to know is that there are three buttons. One to test authentication, one to test using the token for calling the test service, and one for using Basic Authentication instead of the token to call the test service.

Here is an image of the page rendered in a browser.

AuthenticationTokenService html and JavaScript

Here is the source code.

<!DOCTYPE html>
<html>
<head>
    <title>JavaScript Client</title>
    <meta charset="utf-8" />
    <script type="text/javascript" src="/Scripts/jquery-2.1.4.js"></script>
    <script type="text/javascript" src="/Scripts/knockout-3.4.0.debug.js"></script>
    <script type="text/javascript">
        var ViewModel = function () {
            var _vm = this;
            _vm.user = ko.observable();
            _vm.password = ko.observable();
            _vm.basicAuth = ko.computed(function () {
                return "Basic " + btoa(_vm.user() + ":" + _vm.password());
            });
            // I am just sticking the token in a local variable,
            // but you might want to save it in a cookie.
            _vm.token = ko.observable();
            _vm.getResponse = ko.observable();
            _vm.postResponse = ko.observable();
            _vm.onAuthClick = function () {
                $.ajax({
                    method: "POST",
                    url: "/Services/AuthenticationTokenService.svc/Authenticate",
                    contentType: "application/json",
                    context: document.body,
                    data: JSON.stringify({
                        User: _vm.user(),
                        Password: _vm.password()
                    }),
                    success: function (data) {
                        _vm.token(data);
                    },
                    failure: function (err) { alert(err.responseText); },
                    error: function (err) { alert(err.responseText); }
                });
            };
            _vm.onTestGetWithTokenClick = function () {
                $.ajax({
                    url: "/Services/Test1Service.svc/TestGet",
                    contentType: "application/json",
                    context: document.body,
                    beforeSend: function (request) { request.setRequestHeader("Token", _vm.token()); },
                    success: function (data) {
                        _vm.getResponse(data);
                    },
                    failure: function (err) { alert(err.responseText); },
                    error: function (err) { alert(err.responseText); }
                });
            };
            _vm.onTestPostWithBasicAuthClick = function () {
                $.ajax({
                    method: "POST",
                    url: "/Services/Test1Service.svc/TestPost",
                    contentType: "application/json",
                    context: document.body,
                    beforeSend: function (request) { request.setRequestHeader("Authorization", _vm.basicAuth()); },
                    success: function (data) {
                        _vm.postResponse(data);
                    },
                    failure: function (err) { alert(err.responseText); },
                    error: function (err) { alert(err.responseText); }
                });
            };
        };
        $(function () {
            ko.applyBindings(new ViewModel());
        });
    </script>
</head>
<body>
    <div>
        <input type="text" data-bind="value: user" placeholder="Enter your username here . . ." />
        <input type="password" data-bind="value: password" placeholder="Enter your password here . . ." />
        <input type="button" value="Authenticate" data-bind="click: onAuthClick" />
    </div>
    <p>Token: <span data-bind="text: token"></span></p>
    <input type="button" value="Test Get w/ Token" data-bind="click: onTestGetWithTokenClick" />
    <p>Test Get Response: <span data-bind="text: getResponse"></span></p>
    <input type="button" value="Test Post w/ Basic Auth" data-bind="click: onTestPostWithBasicAuthClick" />
    <p>Test Post Response: <span data-bind="text: postResponse"></span></p>
</body>
</html>

Authentication Token Service for WCF Services (Part 5 – Adding SSL)

In the previous article, Basic Token Service for WCF Services (Part 4 – Supporting Basic Authentication), we implemented Basic Authentication. And in the articles before that, our credentials were in the body of the http request. That means we have a huge security issue. Credentials are passing as clear text. This is very, very, very (insert a few thousand more very’s) bad. We need to enabled SSL.

I am going to assume that you know how to do this in production on IIS. I am going to show you how to do this in your development environment.

Download this project here: WCF BTS SSL

Setting Up Visual Studio for SSL

First, let’s get this working in your project. Visual Studio uses needs to launch your project in IIS Express as an SSL site.

  1. In Visual Studio, highlight your project in Solution Explorer.
  2. Press F4 to get the project properties.
  3. Set SSL to true. Notice an SSL url is created on a new port.
ProjectProperties

Setting Up Web Services for SSL

The web.config is where the WCF endpoints are configured. They are currently configured only for HTTP and not HTTPS. So let’s make some web.config edits.

  1. Add an Binding configuration with the security mode set to Transport.
  2. So set the clientCredentialType to none. Remember, we are not using IIS to handle authentication, but instead, we are handling authentication in the service.
  3. use webHttpBinding because We are using JSON and ReST-like (not full ReST) WCF services.
  4. Configure the endpoints to use the newly created Binding configuration.

Here is the complete web.config. The changed or added lines are highlighted.
Changed: Lines 17, 20
Added: Lines 47-55

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
  </configSections>
  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
  </appSettings>
  <system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5" />
  </system.web>
  <system.serviceModel>
    <services>
      <service name="WcfSimpleTokenExample.Services.AuthenticationTokenService" behaviorConfiguration="ServiceBehaviorHttp">
        <endpoint address="" behaviorConfiguration="AjaxEnabledBehavior" binding="webHttpBinding" bindingConfiguration="webBindingSSL" contract="WcfSimpleTokenExample.Services.AuthenticationTokenService" />
      </service>
      <service name="WcfSimpleTokenExample.Services.Test1Service" behaviorConfiguration="ServiceRequiresTokenBehaviorHttp">
        <endpoint address="" behaviorConfiguration="AjaxEnabledBehavior" binding="webHttpBinding" bindingConfiguration="webBindingSSL" contract="WcfSimpleTokenExample.Services.Test1Service" />
      </service>
    </services>
    <behaviors>
      <endpointBehaviors>
        <behavior name="AjaxEnabledBehavior">
          <webHttp helpEnabled="true" />
        </behavior>
      </endpointBehaviors>
      <serviceBehaviors>
        <behavior name="ServiceBehaviorHttp">
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
        <behavior name="ServiceRequiresTokenBehaviorHttp">
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
          <TokenValidationBehaviorExtension />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <extensions>
      <behaviorExtensions>
        <add name="TokenValidationBehaviorExtension"
          type="WcfSimpleTokenExample.Behaviors.TokenValidationBehaviorExtension, WcfSimpleTokenExample, Version=1.0.0.0, Culture=neutral"/>
      </behaviorExtensions>
    </extensions>
    <bindings>
      <webHttpBinding>
        <binding name="webBindingSSL">
          <security mode="Transport">
            <transport clientCredentialType="None"/>
          </security>
        </binding>
      </webHttpBinding>
    </bindings>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="false" multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true" />
    <directoryBrowse enabled="true" />
  </system.webServer>
  <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
      <parameters>
        <parameter value="v11.0" />
      </parameters>
    </defaultConnectionFactory>
    <providers>
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
    </providers>
  </entityFramework>
  <connectionStrings>
    <add name="BasicTokenDbConnection" connectionString="data source=(LocalDB)\v11.0;attachdbfilename=|DataDirectory|\BasicTokenDatabase.mdf;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework" providerName="System.Data.SqlClient" />
  </connectionStrings>
</configuration>

Configuring the SSL Certificate

An SSL certification was generated for me when I built and ran the project. I was able to choose via a pop-up to trust the certificate.

Go on and check out part 6 here: Basic Token Service for WCF Services (Part 6 – A JavaScript client)

Authentication Token Service for WCF Services (Part 4 – Supporting Basic Authentication)

In Authentication Token Service for WCF Services (Part 3 – Token Validation in IDispatchMessageInspector) we showed how to verify our token against a database. The token is a great tool. The authentication service also provides the token based on a post of credentials.

In this article, we are going to add support for Basic Authentication. We aren’t going to do it the standard WCF way, using Transport security. We will keep our security at none, expect the deployment to be https and roll our own code to handle Basic Authentication.

Download this project here: WCF Basic Auth

There are two features we want in order claim support Basic Authentication.

  1. Allow AuthenticationTokenService.svc to create the token by optionally using Basic Authentication.
  2. Allow Basic Authentication as an option to providing a token.

To provide these two features, first we have to understand Basic Authentication. Basic Authentication is a well-known standard that is defined.

Basic Authentication is an html request header. The header is named “Authorization” and the value is as follows:

Basic amFyZWQ6dGVzdHB3

The first part of the Authorization header value is just the word “Basic” followed by a space.
The second part is the username and password concatenated together with a semicolon separator and then Base64 encoded.

jared:testpw
Basic amFyZWQ6dGVzdHB3

Let’s start with a simple class to manage the Basic authentication header, and encoding and decoding it.

using System;
using System.Text;
using WcfSimpleTokenExample.Model;

namespace WcfSimpleTokenExample.Business
{
    public class BasicAuth
    {
        private readonly string _User;
        private readonly string _Password;
        private const string Prefix = "Basic ";

        #region Constructors
        public BasicAuth(string encodedHeader)
            : this(encodedHeader, Encoding.UTF8)
        {
        }

        public BasicAuth(string encodedHeader, Encoding encoding)
        {
            HeaderValue = encodedHeader;
            var decodedHeader = encodedHeader.StartsWith(Prefix)
                ? encoding.GetString(Convert.FromBase64String(encodedHeader.Substring(Prefix.Length)))
                : encoding.GetString(Convert.FromBase64String(encodedHeader));
            var credArray = decodedHeader.Split(':');
            if (credArray.Length > 0)
                _User = credArray[0];
            if (credArray.Length > 1)
                _Password = credArray[1];
        }

        public BasicAuth(string user, string password)
            : this(user, password, Encoding.UTF8)
        {
        }

        public BasicAuth(string user, string password, Encoding encoding)
        {
            _User = user;
            _Password = password;
            HeaderValue = Prefix + Convert.ToBase64String(encoding.GetBytes(string.Format("{0}:{1}", _User, _Password)));
        }
        #endregion

        public Credentials Creds
        {
            get { return _Creds ?? (_Creds = new Credentials { User = _User, Password = _Password }); }
        }
        private Credentials _Creds;

        public string HeaderValue { get; }
    }
}

BasicAuth.cs has constructors that allow for encoding by passing in a username and password and encoding it, as well as constructors that allow for passing in the header value and decoding it to get the username and password.

If we add BasicAuth.cs to our existing WcfSimpleTokenExample project, we can easily use it to support Basic Authentication.

Feature 1 – Basic Authentication for AuthenticationTokenService.svc/Authenticate

By using the BasicAuth.cs class, we can provide support for Basic Authentication in our token service using only 3 lines of code. Below is our new AuthenticationTokenService.svc.cs. Lines 18-20 our the new lines we add.

using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using WcfSimpleTokenExample.Business;
using WcfSimpleTokenExample.Database;
using WcfSimpleTokenExample.Model;

namespace WcfSimpleTokenExample.Services
{
    [ServiceContract]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class AuthenticationTokenService
    {
        [WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare)]
        [OperationContract]
        public string Authenticate(Credentials creds)
        {
            if (creds == null && WebOperationContext.Current != null)
            {
                creds = new BasicAuth(WebOperationContext.Current.IncomingRequest.Headers["Authorization"]).Creds;
            }
            using (var dbContext = new BasicTokenDbContext())
            {
                return new DatabaseTokenBuilder(dbContext).Build(creds);
            }
        }
    }
}

Feature 2 – Using Basic Authentication instead of a token

In our TokenValidationInspector.cs file, we are already validating the token using DatabaseTokenValidator, Now we need to validate the crendentials. We can validate credentials using the DatabaseCrendentialsValidator object that is already being used by AuthenticationTokenBuilder. However, we have to add some conditionaly code to test if a token is provided or if Basic Authorization is provided. If both are ignored, the token takes priority.

To do this, I wrapped the existing lines calling DatabaseTokenValidator into a method called ValidateToken. THen I created a new method called ValidateBasicAuthentication, which we only attempt to call a token isn’t provided.

using System.Net;
using System.Security.Authentication;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Web;
using WcfSimpleTokenExample.Business;
using WcfSimpleTokenExample.Database;
using WcfSimpleTokenExample.Interfaces;

namespace WcfSimpleTokenExample.Behaviors
{
    public class TokenValidationInspector : IDispatchMessageInspector
    {
        public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
        {
            // Return BadRequest if request is null
            if (WebOperationContext.Current == null) { throw new WebFaultException(HttpStatusCode.BadRequest); }

            // Get Token from header
            var token = WebOperationContext.Current.IncomingRequest.Headers["Token"];
            if (!string.IsNullOrWhiteSpace(token))
            {
                ValidateToken(token);
            }
            else
            {
                ValidateBasicAuthentication();
            }
            return null;
        }
        
        private static void ValidateToken(string token)
        {
            using (var dbContext = new BasicTokenDbContext())
            {
                ITokenValidator validator = new DatabaseTokenValidator(dbContext);
                if (!validator.IsValid(token))
                {
                    throw new WebFaultException(HttpStatusCode.Forbidden);
                }
                // Add User ids to the header so the service has them if needed
                WebOperationContext.Current.IncomingRequest.Headers.Add("User", validator.Token.User.Username);
                WebOperationContext.Current.IncomingRequest.Headers.Add("UserId", validator.Token.User.Id.ToString());
            }
        }


        private static void ValidateBasicAuthentication()
        {
            var authorization = WebOperationContext.Current.IncomingRequest.Headers["Authorization"];
            if (string.IsNullOrWhiteSpace(authorization))
            {
                using (var dbContext = new BasicTokenDbContext())
                {
                    var basicAuth = new BasicAuth(authorization);
                    if (!new DatabaseCredentialsValidator(dbContext).IsValid(basicAuth.Creds))
                    {
                        throw new AuthenticationException();
                    }
                }
            }
        }

        public void BeforeSendReply(ref Message reply, object correlationState)
        {
        }
    }
}

The web.config

There are not changes needed for the web.config. Here is a copy of it though, for reference.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
  </configSections>
  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
  </appSettings>
  <system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5" />
  </system.web>
  <system.serviceModel>
    <services>
      <service name="WcfSimpleTokenExample.Services.AuthenticationTokenService" behaviorConfiguration="ServiceBehaviorHttp">
        <endpoint address="" behaviorConfiguration="AjaxEnabledBehavior" binding="webHttpBinding" contract="WcfSimpleTokenExample.Services.AuthenticationTokenService" />
      </service>
      <service name="WcfSimpleTokenExample.Services.Test1Service" behaviorConfiguration="ServiceRequiresTokenBehaviorHttp">
        <endpoint address="" behaviorConfiguration="AjaxEnabledBehavior" binding="webHttpBinding" contract="WcfSimpleTokenExample.Services.Test1Service" />
      </service>
    </services>
    <behaviors>
      <endpointBehaviors>
        <behavior name="AjaxEnabledBehavior">
          <webHttp helpEnabled="true" />
        </behavior>
      </endpointBehaviors>
      <serviceBehaviors>
        <behavior name="ServiceBehaviorHttp">
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
        <behavior name="ServiceRequiresTokenBehaviorHttp">
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
          <TokenValidationBehaviorExtension />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <extensions>
      <behaviorExtensions>
        <add name="TokenValidationBehaviorExtension"
          type="WcfSimpleTokenExample.Behaviors.TokenValidationBehaviorExtension, WcfSimpleTokenExample, Version=1.0.0.0, Culture=neutral"/>
      </behaviorExtensions>
    </extensions>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="false" multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true" />
    <directoryBrowse enabled="true" />
  </system.webServer>
  <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
      <parameters>
        <parameter value="v11.0" />
      </parameters>
    </defaultConnectionFactory>
    <providers>
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
    </providers>
  </entityFramework>
  <connectionStrings>
    <add name="BasicTokenDbConnection" connectionString="data source=(LocalDB)\v11.0;attachdbfilename=|DataDirectory|\BasicTokenDatabase.mdf;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework" providerName="System.Data.SqlClient" />
  </connectionStrings>
</configuration>

Testing Basic Authentication with PostMan

Now we an test that this is working using PostMan. Our PostMan call is similar to what we did in previous articles, but instead of passing a token header, we set Basic Authentication, which sets the Authorization header for us (yes, you could have set the Authorization header manually.)

You could create the Authorization header yourself, but PostMan will create it for you if you click the Authorization and select Basic Auth. Enter your username and password and click update.

PostManBasicAuth

All this does it create an Authorization header for you. You can see this by clicking on the Headers tab in PostMan.

PostManBasicAuthHeader

Go ahead and click Send and you will get your authentication.

Notice the url is https in the image. I haven’t shown you how to do that yet. That is in part 5 here: Authentication Token Service for WCF Services (Part 5 – Adding SSL)

Hidden Cyclomatic Complexity due to Parameter Value Coverage

Cyclomatic Complexity

Cyclomatic complexity is the number of branches found in code.

For example:

public int Add(int x, int y)
{
     return x + y;
}

This appears to have a cyclomatic complexity of 1 as there are no branches in your code. One test will give you 100% code coverage.

Detecting Hidden Cyclomatic Complexity

If you have read about Parameter Value Coverage (PVC) you would be aware that some code will do different things without branching in your code. Perhaps the branch occurs in the underlying code. This is still complexity that your code needs to be tested for.

Example 1

Look at the above Add(int x, int y) method. This appears to have a cyclomatic complexity of 1 as there are no branches in this code. One test will provide 100% code coverage if you count coverage by lines.

However, what if your coverage includes different possibilities for the different possible values of your method parameters? What are the possibilities for an int? Well, this example is in C#, so we will assume C# rules. In C#, an int can’t be null. It can be positive, negative or 0. It also has a max value and a minimum value. That is 5 different options that may be involved in Cyclomatic Complexity.

int result = Add(2147483647, 1);

The above code will not result in the answer being 2147483648.

However, the code doesn’t branch if the options are positive, negative, or 0. They code only behaves different if the combination of both values overflow the integer by going above int.MaxValue or below int.MinValue. So the Cyclomatic complexity is 3. It isn’t 1 as most people would assume at first glance.

Example 2

Also look at this simple divide method. This appears to have a cyclomatic complexity of 1 as there are no branches in this code. One test will provide 100% code coverage if you count coverage by lines. However, your code does react differently due to different possibilities for the different possible values of your method parameters.

public int divide(int x, int y)
{
     return x / y;
}

In the above method what happens when either parameter value is 0? Will your code behave the same as if two non-zero values are passed in? Or is there hidden cyclomatic complexity?

Taking into account the hidden cyclomatic complexity, do you still feel this code will never branch? Or do different parameter values cause it to branch? What is the Cylomatic complexity of this method?

If the second value is 0, the code is going to throw a DivideByZeroException. Really, that is the only difference. Since this is divide, it is impossible to overflow the integer, so int.MaxValue and int.MinValue don’t come into play. So the cyclomatic complexity is 2, not 1.

Conclusion

Cyclomatic Complexity is a great tool to measure the complexity of you code. However, failure to test and measure for different possible parameter values can give one a false sense of simplicity and an incorrect Cyclomatic Complexity score.

Branching can occur even in a single line of code. You have been warned!

How to get and set private fields or properties in C#

Sometimes you want to access a private member of an object. If you were the author of such object, you would simply change the encapsulation from private to public, or protected if you just want access from a child. However, what if you don’t have access to the object. What if it is one of the standard .NET library objects. You can’t change it. What are your options?

  1. Rewrite the entire class. (Not easy and I don’t recommend it)
  2. Recreate the value somehow (which might not even be possible)

Well, guess what. Microsoft left a nice workaround to encapsulation in its implementation of Reflection.

Here is a nice class you can use to get the value of any private member.

using System;
using System.Linq;
using System.Reflection;

namespace Rhyous.TextBlock.Business
{
    public class PrivateValueAccessor
    {
        public static BindingFlags Flags = BindingFlags.Instance
                                           | BindingFlags.GetProperty
                                           | BindingFlags.SetProperty
                                           | BindingFlags.GetField
                                           | BindingFlags.SetField
                                           | BindingFlags.NonPublic;

        /// <summary>
        /// A static method to get the PropertyInfo of a private property of any object.
        /// </summary>
        /// <param name="type">The Type that has the private property</param>
        /// <param name="propertyName">The name of the private property</param>
        /// <returns>PropertyInfo object. It has the property name and a useful GetValue() method.</returns>
        public static PropertyInfo GetPrivatePropertyInfo(Type type, string propertyName)
        {
            var props = type.GetProperties(Flags);
            return props.FirstOrDefault(propInfo => propInfo.Name == propertyName);
        }

        /// <summary>
        /// A static method to get the value of a private property of any object.
        /// </summary>
        /// <param name="type">The Type that has the private property</param>
        /// <param name="propertyName">The name of the private property</param>
        /// <param name="o">The instance from which to read the private value.</param>
        /// <returns>The value of the property boxed as an object.</returns>
        public static object GetPrivatePropertyValue(Type type, string propertyName, object o)
        {
            return GetPrivatePropertyInfo(type, propertyName).GetValue(o);
        }

        /// <summary>
        /// A static method to get the FieldInfo of a private field of any object.
        /// </summary>
        /// <param name="type">The Type that has the private field</param>
        /// <param name="fieldName">The name of the private field</param>
        /// <returns>FieldInfo object. It has the field name and a useful GetValue() method.</returns>
        public static FieldInfo GetPrivateFieldInfo(Type type, string fieldName)
        {
            var fields = type.GetFields(Flags);
            return fields.FirstOrDefault(feildInfo => feildInfo.Name == fieldName);
        }

        /// <summary>
        /// A static method to get the FieldInfo of a private field of any object.
        /// </summary>
        /// <param name="type">The Type that has the private field</param>
        /// <param name="fieldName">The name of the private field</param>
        /// <param name="o">The instance from which to read the private value.</param>
        /// <returns>The value of the property boxed as an object.</returns>
        public static object GetPrivateFieldValue(Type type, string fieldName, object o)
        {
            return GetPrivateFieldInfo(type, fieldName).GetValue(o);
        }
    }
}

And here is how to use it.

Imagine you have a class with a private Field and a private property.

public class A
{
    private int MyPrivateProperty
    {
        get { return _MyPrivateField; }
        set { _MyPrivateField = value; }
    } private int _MyPrivateField = 27;
}

You can access the value as follows:

    var a = new A();
    // Get values
    int privateFieldValue = (int)PrivateValueAccessor.GetPrivateFieldValue(typeof(A), "_MyPrivateField", a);
    int privatePropValue = (int)PrivateValueAccessor.GetPrivatePropertyValue(typeof(A), "MyPrivateProperty", a);

    // Set Values
    PrivateValueAccessor.GetPrivateFieldInfo(typeof(A), "_MyPrivateField").SetValue(a, 11);
    PrivateValueAccessor.GetPrivatePropertyInfo(typeof(A), "MyPrivateProperty").SetValue(a, 7);

Access private fields or properties from a base class

OK, so now that we have this class, you can imagine that you can now use it in a child, if you have no other choice, in order to expose A.MyPrivateProp.

public class B : A
{
    public int ExposedProperty
    {
        get { return (int)PrivateValueAccessor.GetPrivateFieldValue(typeof(A), "_MyPrivateField", this); }
        set { PrivateValueAccessor.GetPrivateFieldInfo(typeof(A), "_MyPrivateField").SetValue(this, value); }
    }
}

Now you have exposed the private value in your child class. You can call it as normal.

            var b = new B();
            b.ExposedProperty = 20;

Here is what it looks like in the debugger before you set it.

b    {B}    B
    base    {B}    A {B}
        _MyPrivateField      27    int
        MyPrivateProperty    27    int
        ExposedProperty      27    int
        b.ExposedProperty    27    int

And after setting B.ExposedProperty to 20, it looks like this.

b    {B}    B
    base    {B}    A {B}
        _MyPrivateField      20    int
        MyPrivateProperty    20    int
        ExposedProperty      20    int
        b.ExposedProperty    20    int

Conclusion

You now have a serviceable workaround for a getting and setting a private field or property.

It really isn’t going to perform well, since it uses Reflection, but if it is a single value that you only set once, you won’t have a performance problem.

Since it is so easy to break encapsulation with Reflection, it makes me wonder what the point of encapsulation is in C#? But it still has it’s purposes, I know.

Tips for using the Google Calendar API with C#

See my previous post: Interfacing with the Google Calendar API using C#

Tip #1 – Google Calendar API is set to ReadOnly in the example

I needed to edit, not just read.
Change line 23 in the code above:

//static string[] Scopes = { CalendarService.Scope.CalendarReadonly }; // I needed more than read only
static string[] Scopes = { CalendarService.Scope.Calendar };

Tip #2 – Your App’s Security Permission to use the Google Calendar API

My application stopped working. I had to revoke my projects permission and then run the code again so I was prompted to accept permission. Sometimes I had to re-run the code twice to get the prompt.

Go here to revoke your permissions: https://security.google.com/settings/security/permissions

Tip #3 – How to find a Calendar by name

You can get a list of Calendars. The Summary property is where the Calendar title is stored.

    // . . . Authentication here

    // Create Calendar Service.
    var service = new CalendarService(new BaseClientService.Initializer()
    {
        HttpClientInitializer = credential,
        ApplicationName = ApplicationName,
    });


    var list = service.CalendarList.List().Execute();
    var myCalendar = list.Items.SingleOrDefault(c => c.Summary == "My Calendar Name");
            
    // . . . do stuff with your calendar

Tip #4 – How to add an event

I thought it was weird that the example didn’t actually have you add an event. To add an event:

  1. First read Tip #1.
  2. Use this code:
    var list = service.CalendarList.List().Execute();
    var myCalendar = list.Items.SingleOrDefault(c => c.Summary == "My Calendar");
            
    if (myCalendar != null)
    {
        Event calEvent = new Event
        {
            Summary = "Awesome Party",
            Location = "My House",
            Start = new EventDateTime
            {
                DateTime = new DateTime(2015, 5, 20, 19, 00, 0)
            },
            End = new EventDateTime
            {
                DateTime = new DateTime(2015, 5, 20, 23, 59, 0)
            },
            Recurrence = new List<string>()
        };
        var newEventRequest = service.Events.Insert(calEvent, myCalendar.Id);
        var eventResult = newEventRequest.Execute();
    }

Interfacing with the Google Calendar API using C#

I needed to script something with Google Calendar, so naturally I headed over to their API page. I found a quick start document and it is a creative commons license, so I can re-post it here:

See my tips after you read this document! See my previous post: Tips for using the Google Calendar API with C#

—————-
Complete the steps described in the rest of this page, and in about five minutes you’ll have a simple .NET console application that makes requests to the Google Calendar API.

Prerequisites

To run this quickstart you’ll need:

  • Visual Studio 2013 or later.
  • Access to the internet and a web browser.
  • A Google account with Google Calendar enabled.

Step 1: Enable the Calendar API

  1. Use this wizard
    to create or select a project in the Google Developers Console and
    automatically enable the API.
  2. In the sidebar on the left, select Consent screen. Select an
    EMAIL ADDRESS and enter a PRODUCT NAME if not already set and click
    the Save button.
  3. In the sidebar on the left, select Credentials and click Create new
    Client ID
    .
  4. Select the application type Installed application, the installed
    application type Other, and click the Create Client ID button.
  5. Click the Download JSON button under your new client ID. Rename it
    to client_secret.json.

Step 2: Install the Google Client Library

  1. Create a new Visual C# Console Application project in Visual Studio.
  2. From the Package Manager Console, with package source set to “nuget.org”
    run the following command:
PM> Install-Package Google.Apis.Calendar.v3

Step 3: Set up the sample

  1. Copy client_secret.json (downloaded in Step 1) into your project directory.
  2. Refresh the Solution Explorer to show the client_secret.json that was
    copied in.
  3. From Solution Explorer right click on client_secret.json and select
    the Include In Project option.
  4. With client_secret.json still selected go to the Properties window and set
    the Copy to Output Directory field to Copy always.
  5. Replace the contents of Program.cs with the following code.
using Google.Apis.Auth.OAuth2;
using Google.Apis.Calendar.v3;
using Google.Apis.Calendar.v3.Data;
using Google.Apis.Services;
using Google.Apis.Util.Store;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace CalendarQuickstart
{
  /// <summary>
  /// Google Calendar API quickstart application that retrieves the next ten
  /// events of the authenticated user's primary calendar and prints the
  /// summary and start datetime/date of each.
  /// </summary>
  class Program
  {
    static string[] Scopes = { CalendarService.Scope.CalendarReadonly };
    static string ApplicationName = "Calendar API Quickstart";


    static void Main(string[] args)
    {
      UserCredential credential;

      using (var stream = new FileStream("client_secret.json", FileMode.Open,
          FileAccess.Read))
      {
        string credPath = System.Environment.GetFolderPath(System.Environment
          .SpecialFolder.Personal);
        credPath = Path.Combine(credPath, ".credentials");

        credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
           GoogleClientSecrets.Load(stream).Secrets,
          Scopes,
          "user",
          CancellationToken.None,
          new FileDataStore(credPath, true)).Result;

        Console.WriteLine("Credential file saved to: " + credPath);
      }

      // Create Calendar Service.
      var service = new CalendarService(new BaseClientService.Initializer()
      {
        HttpClientInitializer = credential,
        ApplicationName = ApplicationName,
      });

      // Define parameters of request.
      EventsResource.ListRequest request = service.Events.List("primary");
      request.TimeMin = DateTime.Now;
      request.ShowDeleted = false;
      request.SingleEvents = true;
      request.MaxResults = 10;
      request.OrderBy = EventsResource.ListRequest.OrderByEnum.StartTime;

      Console.WriteLine("Upcoming events:");
      Events events = request.Execute();
      if (events.Items.Count > 0)
      {
        foreach (var eventItem in events.Items)
        {
          string when = eventItem.Start.DateTime.ToString();
          if (String.IsNullOrEmpty(when))
          {
            when = eventItem.Start.Date;
          }
          Console.WriteLine("{0} ({1})", eventItem.Summary, when);
        }
      }
      else
      {
        Console.WriteLine("No upcoming events found.");
      }
      Console.Read();
    }
  }
}

Step 4: Run the sample

Run the sample by clicking Start in the Visual Studio toolbar.

The first time you run the sample it will prompt you to authorize access.

  1. A browser window will open prompting you to login if you are not already
    logged into your Google account. If you are logged into multiple Google
    accounts, you will be asked to select one account to use for the authorization.
  2. Click the Accept button.

Authorization information is stored on the file system, so subsequent
executions will not prompt for authorization.

Further reading

Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 3.0 License, and code samples are licensed under the Apache 2.0 License. For details, see our Site Policies.

Setting File Properties in a NuGet Package: Build Action, Copy to Output Directory, Custom Tool

So I have a bunch of files in a NuGet package that need the File Properties set as follows:

Build Action Content
Copy to Output Directory Copy if newer
Custom Tool
Custom Tool Namespace

I am using the NuGet package Project that you can find in the Online projects.

I was able to set these values in a NuGet package as follows using the Install.ps1 PowerShell script. I found this out thanks to Workabyte’s answer on StackOverflow

$item = $project.ProjectItems.Item("MyContentFile.xml")
$item.Properties.Item("BuildAction").Value = 2
$item.Properties.Item("CopyToOutputDirectory").Value = 2
$item.Properties.Item("CustomTool").Value = ""

I would just set something to what I wanted it to be, then I would look at its value.

Here is my full Install.ps1

# Runs every time a package is installed in a project

param($installPath, $toolsPath, $package, $project)

# $installPath is the path to the folder where the package is installed.
# $toolsPath is the path to the tools directory in the folder where the package is installed.
# $package is a reference to the package object.
# $project is a reference to the project the package was installed to.

function SetFilePropertiesRecursively
{
	$folderKind = "{6BB5F8EF-4483-11D3-8BCF-00C04F8EC28C}";
	foreach ($subItem in $args[0].ProjectItems)
	{
		$path = $args[1]
	    if ($subItem.Kind -eq $folderKind)
		{
			SetFilePropertiesRecursively $subItem ("{0}{1}{2}" -f $path, $args[0].Name, "\")
		}
		else
		{
			Write-Host -NoNewLine ("{0}{1}{2}" -f $path, $args[0].Name, "\")
			SetFileProperties $subItem 2 2 ""
		}
	}
}

function SetFileProperties
{
	param([__ComObject]$item, [int]$buildAction, [int]$copyTo, [string]$customTool)
	Write-Host $item.Name
	Write-Host "  Setting Build Action to Content"
	$item.Properties.Item("BuildAction").Value = $buildAction
	Write-Host "  Setting Copy To Output Directory to Copy if newer"
	$item.Properties.Item("CopyToOutputDirectory").Value = $copyTo
	Write-Host "  Setting Custom Tool to blank"
	$item.Properties.Item("CustomTool").Value = $customTool
}

SetFilePropertiesRecursively $project.ProjectItems.Item("Globalization")
SetFilePropertiesRecursively $project.ProjectItems.Item("Styles")
SetFileProperties $project.ProjectItems.Item("App.xaml") 4 0 "MSBuild:Compile"

Life is good.

Row Tests or Paramerterized Tests (MsTest) – Xml

In a previous post, I discussed Parameter Value Coverage (PVC). One of the easiest ways to add PVC to your test suite is to use Row Tests, sometimes called Parameterized Tests. Row test is the idea of writing a single unit test, but passing many different values in.

Different testing frameworks implement row tests differently.

MsTest uses an attribute called DataResourceAttribute. This supports anything from a csv, Excel file or xml, to a full-blown database.

For a single Unit Test, NUnit’s Row tests are far superior. However, for a larger test project, you will see that DataSourceAttribute with external data sources, scales nicely and compares to NUnits TestCaseSource. However, it is not as easy to get it right the first time. It needs a step by step tutorial.

Step 1 – Create a the Project

  1. In Visual Studio click File | New | Project.
  2. Select Unit Test Project for C#.
  3. Give it a name and a path and click OK.

Step 2 – Add an Xml file

  1. Create a folder in your visual studio project called Data.
  2. Right-click on the data folder and choose Add | New Item.
  3. Create new Xml file named: Data.xml
  4. Add the following to the Xml.
<?xml version="1.0" encoding="utf-8" ?>
<Rows xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:x="urn:Row">
  <!-- Schema -->
  <xsd:schema targetNamespace="urn:Row" attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema" >
    <xsd:element name="Row">
      <xsd:complexType>
        <xsd:sequence>
          <xsd:element type="xsd:int" name="Value1"/>
          <xsd:element type="xsd:int" name="Value2"/>
          <xsd:element type="xsd:int" name="ExpectedValue"/>
          <xsd:element type="xsd:string" name="Message"/>
        </xsd:sequence>
      </xsd:complexType>
    </xsd:element>
  </xsd:schema>
  <!--End Schema-->
  <x:Row>
    <x:Value1>3</x:Value1>
    <x:Value2>2</x:Value2>
    <x:ExpectedValue>2</x:ExpectedValue>
    <x:Message>2 is less than 3</x:Message>
  </x:Row>
  <x:Row>
    <x:Value1>-1</x:Value1>
    <x:Value2>0</x:Value2>
    <x:ExpectedValue>-1</x:ExpectedValue>
    <x:Message>-1 less than 0</x:Message>
  </x:Row>
  <x:Row>
    <x:Value1>10</x:Value1>
    <x:Value2>5</x:Value2>
    <x:ExpectedValue>5</x:ExpectedValue>
    <x:Message>5 is less than 10</x:Message>
  </x:Row>
</Rows>

Note: This Xml is designed as such so the Schema is inline. That allows us to specify the data type.

Step 3 – Set Xml File Properties

The XML file needs to be copied on build.

  1. Right-click on the Xml file and choose Properties.
  2. Change the Copy to output directory to: Copy if newer

Step 4 – Add a Unit Test method

Note: We won’t have a real project to test. We will just test Math.Min() for an example.

  1. Add a reference to System.Data.
  2. Add the TestContext property. (See line 9 below)
  3. Add a DataSource attribute to the test method. (See line 12 below)
    Notice that is uses Row not Rows (it doesn’t use the root element but the second element).
  4. Use TestContext.DataRow[0] to get the first column. (See line 16 below)
    Note: You can also access the column by the column name we used: TestContext.DataRow[Value1]

  5. Assign variables for the rest of the columns. (See lines 16-19 below)
  6. Add the test and the assert. (See lines 22 and 25)
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace MsTestRowTestXml
{
    [TestClass]
    public class UnitTest1
    {
        public TestContext TestContext { get; set; }

        [TestMethod]
        [DataSource("Microsoft.VisualStudio.TestTools.DataSource.XML", @"Data\Data.xml", "Row", DataAccessMethod.Sequential)]
        public void TestMethod1()
        {
            // Arrange
            int a = (int)TestContext.DataRow[0];
            int b = (int)TestContext.DataRow[1];
            int expected = (int)TestContext.DataRow[2];
            string message = TestContext.DataRow[3].ToString();

            // Act
            var actual = Math.Min(a, b);

            // Assert
            Assert.AreEqual(expected, actual, message);
        }
    }
}

You finished! Good job!.

Use Common Xml files for Parameter Value Coverage

While this method involved way more steps than anything with NUnit to set up, tt can actually be a bit quicker for subsequent tests and quite useful when testing larger projects. Once you have the Xml files setup, you can reuse them for many methods. For example, for every method that takes a long, you could use the same DataSource to get Parameter Value Coverage (PVC).

<?xml version="1.0" encoding="utf-8" ?>
<Rows xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:x="urn:Row">
  <!-- Schema -->
  <xsd:schema targetNamespace="urn:Row" attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema" >
    <xsd:element name="Row">
      <xsd:complexType>
        <xsd:sequence>
          <xsd:element type="xsd:long" name="Value"/>
          <xsd:element type="xsd:string" name="Message"/>
        </xsd:sequence>
      </xsd:complexType>
    </xsd:element>
  </xsd:schema>
  <!--End Schema-->
  <x:Row>
    <x:Value>2147483648</x:Value>
    <x:Message>One more than int.MaxValue</x:Message>
  </x:Row>
  <x:Row>
    <x:Value>-2147483649</x:Value>
    <x:Message>One less than int.MinValue</x:Message>
  </x:Row>
  <x:Row>
    <x:Value>9223372036854775807</x:Value>
    <x:Message>long.MaxValue</x:Message>
  </x:Row>
  <x:Row>
    <x:Value>-9223372036854775808</x:Value>
    <x:Message>long.MinValue</x:Message>
  </x:Row>
  <x:Row>
    <x:Value>0</x:Value>
    <x:Message>0 (zero)</x:Message>
  </x:Row>
  <x:Row>
    <x:Value>1</x:Value>
    <x:Message>1 (one)</x:Message>
  </x:Row>
  <x:Row>
    <x:Value>2</x:Value>
    <x:Message>2 (one)</x:Message>
  </x:Row>
  <x:Row>
    <x:Value>-1</x:Value>
    <x:Message>-1 (minus one)</x:Message>
  </x:Row>
  <x:Row>
    <x:Value>-2</x:Value>
    <x:Message>-2, -2 (minus one)</x:Message>
  </x:Row>
</Rows>

Row Tests or Paramerterized Tests (MsTest) – CSV

In a previous post, I discussed Parameter Value Coverage (PVC). One of the easiest ways to add PVC to your test suite is to use Row Tests, sometimes called Parameterized Tests. Row test is the idea of writing a single unit test, but passing many different values in.

Different testing frameworks implement row tests differently.

MsTest uses an attribute called DataResourceAttribute. This supports anything from a csv, Excel file or xml, to a full-blown database.

For a single Unit Test, NUnit’s Row tests are far superior. However, for a larger test project, you will see that DataSourceAttribute with external data sources, scales nicely and compares to NUnits TestCaseSource. However, it is not as easy to get it right the first time. It needs a step by step tutorial.

Step 1 – Create a the Project

  1. In Visual Studio click File | New | Project.
  2. Select Unit Test Project for C#.
  3. Give it a name and a path and click OK.

Step 2 – Add a csv file

  1. Create a folder in your visual studio project called Data.
  2. Right-click on the data folder and choose Add | New Item.
  3. Create new text file named: Data.csv
  4. Add the following to the csv.
Value1, Value2, ExpectedMinValue, Message
1,10, 1, 1 is less th an 10.
192, 134, 134, 134 is less than 192.
101, 99, 99, 99 is less than 101.
77, 108, 77, 77 is less than 108.
45, 37, 37, 37 is less than 34.
12, 18, 12, 12 is less than 18.

Step 3 – Save the CSV file with the correct encoding

Note: The CSV file needs to be saved with an encoding that doesn’t add junk characters.

  • Click File | Advanced Save Options.
  • Choose this Encoding option: Unicode (UTF-8 without signature) – Codepage 65001
  • Click OK and then click save.
  • Step 4 – Set CSV File Properties

    The CSV file needs to be copied on build.

    1. Right-click on the CSV file and choose Properties.
    2. Change the Copy to output directory to: Copy if newer

    Step 5 – Add a Unit Test method

    Note: We won’t have a real project to test. We will just test Math.Min() for an example.

    1. Add a reference to System.Data.
    2. Add the TestContext property. (See line 9 below)
    3. Add a DataSource attribute to the test method. (See line 12 below)
    4. Use TestContext.DataRow[0] to get the first column. (See line 16 below)
      Note: You can also access the column by the column name we used: TestContext.DataRow[Value1]

    5. Assign variables for the rest of the columns. (See lines 16-19 below)
    6. Add the test and the assert. (See lines 22 and 25)
    using System;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    
    namespace MsTestRowTestExample
    {
        [TestClass]
        public class UnitTest1
        {
            public TestContext TestContext { get; set; }
    
            [TestMethod]
            [DataSource("Microsoft.VisualStudio.TestTools.DataSource.CSV", @"Data\Data.csv", "Data#csv", DataAccessMethod.Sequential)]
            public void TestMethod1()
            {
                // Arrange
                int a = Convert.ToInt32(TestContext.DataRow[0]);
                int b = Convert.ToInt32(TestContext.DataRow[1]);
                int expected = Convert.ToInt32(TestContext.DataRow[2]);
                string message = TestContext.DataRow[3].ToString();
    
                // Act
                var actual = Math.Min(a, b);
    
                // Assert
                Assert.AreEqual(expected, actual, message);
            }
        }
    }
    

    You finished! Good job!.

    Use Common Csv files for Parameter Value Coverage

    While this method involved way more steps than anything with NUnit to set up, tt can actually be a bit quicker for subsequent tests and quite useful when testing larger projects. Once you have the csv files setup, you can reuse them for many methods. For example, for every method that takes a string, you could use the same DataSource to get Parameter Value Coverage (PVC).

    null, A null string
    "", An empty string, String.Empty, or ""
    " ", One or more spaces " "
    "	", One or more tabs "	"
    "
    ", A new line or Environment.NewLine
    "Hello, world!", A valid string.
    "&*^I#UYLdk1-KNnS1.,Dv0Hhfwelfnzsdase", An invalid or junk string
    গঘ, Double-byte Unicode characters
    

    Combining multiple WSDLs for consumption in a C# client project

    So I added a WebReference for nine different web services. These were all web services for the same product. I will call them from the same client code. So it makes sense to consume them all. Each service got it’s own namespace. Immediately there were problems. Multiple web services exposed the same object. Each instance of the object was in a different namespace. This created a bunch of ambiguous reference errors. Fixing those errors made a mess of the code as I then had to include the namespaces when calling the objects or else have object using statements to determine which object to use in which namespace.

    The I got smart and researched combining WSDLs. I found this MSDN site: Web Services Description Language Tool (Wsdl.exe)

    Turns out that Visual Studio comes with a WSDL.exe. It allows for easily combining multiple WSDLs into one large auto-generated code file. It also has a nice parameter called sharetypes. I bet you can guess what sharetypes does.

    Step 1 – Create a wsdl parameters file

    Here is an exmaple of mine.

    1. I left the settings from the MSN example for nologo, parsableerrors, and sharetypes.
      Note: Setting sharetypes to true is the feature I most needed.
    2. Set it to get the URL from the web.config or app.config.
    3. Set the namespace.
    4. Add a document for each wsdl file.
    5. Set out file.
      <wsdlParameters xmlns="http://microsoft.com/webReference/">
        <appSettingUrlKey>FnoSharpWebServiceUrl</appSettingUrlKey>
        <appSettingBaseUrl>FnoSharpWebServiceBaseUrl</appSettingBaseUrl>
        <namespace>FnoSharp</namespace>
        <nologo>true</nologo>
        <parsableerrors>true</parsableerrors>
        <sharetypes>true</sharetypes>
        <documents>
          <document>http://MyServer:8888/flexnet/services/ActivationService?wsdl</document>
          <document>http://MyServer:8888/flexnet/services/AdminService?wsdl</document>
          <document>http://MyServer:8888/flexnet/services/EntitlementOrderService?wsdl</document>
          <document>http://MyServer:8888/flexnet/services/FlexnetAuthentication?wsdl</document>
          <document>http://MyServer:8888/flexnet/services/LicenseService?wsdl</document>
          <document>http://MyServer:8888/flexnet/services/ManageDeviceService?wsdl</document>
          <document>http://MyServer:8888/flexnet/services/ProductPackagingService?wsdl</document>
          <document>http://MyServer:8888/flexnet/services/UserOrgHierarchyService?wsdl</document>
          <document>http://MyServer:8888/flexnet/services/Version?wsdl</document>
        </documents>
        <out>FnoSharpReference.cs</out>
      </wsdlParameters>
      

    Step 2 – Run wsdl.exe

    1. Open a Developer Command Prompt.
    2. Run this command:
      wsdl.exe /Parameters:FnoSharpWsdls.xml
      

    Now you have a single Reference.cs file that includes code for all your WSDLs.

    Step 3 – Update your Visual Studio Project

    1. Delete all your web references.
    2. Add the Reference.cs to your project
    3. Fix your namespaces.

    Step 4 – Update URL to use an appSetting

    Having a hard coded URL in the code is not a good idea. The Reference.cs file you created will have static URLs. Unfortunately the wsdl.exe doesn’t seem to support doing this for multiple urls. So you should manually replace them.

    1. Add a variable to your appSettings in your web.config or app.config.
      <?xml version="1.0" encoding="utf-8" ?>
      <configuration>
        <appSettings>
          <add key="FnoSharpHost" value="http://MyServer:8888"/>
        </appSettings>
      
        <!-- Other config stuff -->
      
      <configuration>
      
    2. Find and replace all the lines that call your hard coded URL. They look like this. I had 9 WSDLs so I had 9 of these to replace.
          public ActivationService() {
              this.Url = "http://MyServer:8888/flexnet/services/ActivationService";
          }
      

      Here is your find and replace string:

         Find:  this.Url = "http://MyServer:8888
      Replace:  this.Url = ConfigurationManager.AppSettings["FnoSharpHost"] + "
      

      Your methods should now look like this:

          public ActivationService() {
              this.Url = ConfigurationManager.AppSettings["FnoSharpHost"] + "/flexnet/services/ActivationService";
          }
      

    Your done. You now have all your WSDLs combined into one Reference.cs file.

    AutoMapper versus Extension Methods versus Implicit Casts

    Download Project
    Imagine the database code is legacy, can’t be changed, and the Database Person object from the database namespace looks like this:

    using System;
    using System.ComponentModel.DataAnnotations;
    
    namespace WcfToEntityAutomapperExample.DAL.Model
    {
        /// <summary>
        /// Example of an Person object where properties are not defined in a way you want 
        /// to expose via WCF.
        /// </summary>
        class PersonRow
        {
            public int Id { get; set; }
    
            [Required]
            [StringLength(50)]
            public string FName { get; set; }
    
            [Required]
            [StringLength(50)]
            public string MName { get; set; }
    
            [Required]
            [StringLength(50)]
            public string LName { get; set; }
    
            [Required]
            public DateTime BD { get; set; }
    
            public DateTime? DD { get; set; }
        }
    }
    

    You can’t use this in your WCF service, and not just beccause PersonRow, FName and LName just look tacky, though that is reason alone. No, the real problem is ambiguity and confusion. MName isn’t exactly clear. Is it Maiden name, Mother’s last name, or middle name? And what is BD and DD? Such confusion and ambiguity isn’t acceptable in an exposed API.

    So you create a Person DataContract to expose with WCF that looks like this:

    using System;
    using System.Runtime.Serialization;
    
    namespace WcfToEntityAutomapperExample.Services.Model
    {
        [DataContract]
        public class Person
        {
            [DataMember]
            public string FirstName { get; set; }
            [DataMember]
            public string MiddleName { get; set; }
            [DataMember]
            public string LastName { get; set; }
            [DataMember]
            public DateTime DateOfBirth { get; set; }
            [DataMember]
            public DateTime? DateOfDeath { get; set; }
        }
    }
    

    Wow. That will look much better in your exposed WCF API.

    So now there is a problem. We need to convert Person to PersonRow.

    Solving with extension methods

    It would be easy to write extension methods to do this:

    1. Add an extension method

      using WcfToEntityAutomapperExample.DAL.Model;
      using WcfToEntityAutomapperExample.Services.Model;
      
      namespace WcfToEntityAutomapperExample.Extensions
      {
          static class PersonExtensions
          {
              public static PersonRow ToPersonRow(this Person person)
              {
                  return new PersonRow
                  {
                      FName = person.FirstName,
                      MName = person.MiddleName,
                      LName = person.LastName,
                      BD = person.DateOfBirth,
                      DD = person.DateOfDeath
                  };
              }
          }
      }
      
    2. Add a reverse mapping extension method.

      OK. Now we have this extension method and we can use it anywhere we want. However, we forgot. We need to do this in reverse too. We need an extension method for PersonRow to Person. So add this method to PersonExtensions class.

      using WcfToEntityAutomapperExample.DAL.Model;
      using WcfToEntityAutomapperExample.Services.Model;
      
      namespace WcfToEntityAutomapperExample.Extensions
      {
          static class PersonExtensions
          {
              public static PersonRow ToPersonRow(this Person person)
              {
                  return new PersonRow
                  {
                      FName = person.FirstName,
                      MName = person.MiddleName,
                      LName = person.LastName,
                      BD = person.DateOfBirth,
                      DD = person.DateOfDeath
                  };
              }
      
              public static Person ToPerson(this PersonRow personRow)
              {
                  return new Person
                  {
                      FirstName = personRow.FName,
                      MiddleName = personRow.MName,
                      LastName = personRow.LName,
                      DateOfBirth = personRow.BD,
                      DateOfDeath = personRow.DD
                  };
              }
          }
      }
      
    3. Now, you have 40 other objects to do this too.
      Hint: Take a moment to compare this to the AutoMapper method below and ask yourself which is better.

    4. Use the extension method in the web service call.
      using System.Collections.Generic;
      using System.Linq;
      using WcfToEntityAutomapperExample.DAL;
      using WcfToEntityAutomapperExample.DAL.Model;
      using WcfToEntityAutomapperExample.Extensions;
      using WcfToEntityAutomapperExample.Services.Interfaces;
      using WcfToEntityAutomapperExample.Services.Model;
      
      namespace WcfToEntityAutomapperExample.Services
      {
           public class Service1 : IService1
          {
              public void AddPersonExtensionMethod(Person person)
              {
                  using (var dbContext = new PersonDbContext())
                  {
                      dbContext.People.Add(person.ToPersonRow());
                      dbContext.SaveChanges();
                  }
              }
      
              public List<Person> FindExtensionMethod(string lastName)
              {
                  using (var dbContext = new PersonDbContext())
                  {
                      var foundPeopleFromDb = dbContext.People.Where(p => p.LName == lastName).ToList();
                      return foundPeopleFromDb.Select(p => p.ToPerson()).ToList();
                  }
              }
          }
      }
      

    Extension Method Conclusion

    Simple. Easy to use. Easy to read. Makes sense. The extension method name is an important part of this clarity. I used ToPerson and ToPersonRow. But it would also work with AsPerson and AsPersonRow.

    Anybody can read this code and understand it.

    If another field is added it is easy to add to the extension method on a single place so code isn’t strewn about.

    Using AutoMapper

    Why is AutoMapper better than the above extension method? Let’s do the same thing with AutoMapper. You be the judge of whether it is a better solution.

    Well, so far, I can’t find any benefit from AutoMapper.

    Here is what I need to do:

    1. Add AutoMapper library from NuGet. That adds a dll and another dependency to maintain.
    2. Create a static class to configure AutoMapper mappings: AutoMapperConfig.cs.
    3. Add mappings both ways: From Person to PersonRow and from PersonRow to Person.
      using AutoMapper;
      using WcfToEntityAutomapperExample.DAL.Model;
      using WcfToEntityAutomapperExample.Services.Model;
      
      namespace WcfToEntityAutomapperExample.Map
      {
          public static class AutoMapperConfig
          {
              internal static void RegisterMappings()
              {
                  Mapper.CreateMap<Person, PersonRow>()
                      .ForMember(dest => dest.FName, opt => opt.MapFrom(src => src.FirstName))
                      .ForMember(dest => dest.MName, opt => opt.MapFrom(src => src.MiddleName))
                      .ForMember(dest => dest.LName, opt => opt.MapFrom(src => src.LastName))
                      .ForMember(dest => dest.BD, opt => opt.MapFrom(src => src.DateOfBirth))
                      .ForMember(dest => dest.DD, opt => opt.MapFrom(src => src.DateOfDeath)).ReverseMap();
              }
          }
      }
      
      

      Now, you have 40 other objects to do this too.
      Hint: Take a moment to compare this to the extension method above and ask yourself which is better.

    4. Find a global location to call AutoMapperConfig.cs: Global.asax/Global.asax.cs.
      Note: If you don’t have a Global.asax/Global.asax.cs, then you need to add this.

      using System;
      using System.Web;
      using WcfToEntityAutomapperExample.Map;
      
      namespace WcfToEntityAutomapperExample
      {
          public class Global : HttpApplication
          {
              protected void Application_Start(object sender, EventArgs e)
              {
                  AutoMapperConfig.RegisterMappings();
              }
      
              protected void Session_Start(object sender, EventArgs e)
              {
      
              }
      
              protected void Application_BeginRequest(object sender, EventArgs e)
              {
      
              }
      
              protected void Application_AuthenticateRequest(object sender, EventArgs e)
              {
      
              }
      
              protected void Application_Error(object sender, EventArgs e)
              {
      
              }
      
              protected void Session_End(object sender, EventArgs e)
              {
      
              }
      
              protected void Application_End(object sender, EventArgs e)
              {
      
              }
          }
      }
      
    5. Call it in your service.
      using System.Collections.Generic;
      using System.Linq;
      using AutoMapper;
      using WcfToEntityAutomapperExample.DAL;
      using WcfToEntityAutomapperExample.DAL.Model;
      using WcfToEntityAutomapperExample.Extensions;
      using WcfToEntityAutomapperExample.Services.Interfaces;
      using WcfToEntityAutomapperExample.Services.Model;
      
      namespace WcfToEntityAutomapperExample.Services
      {
           public class Service1 : IService1
          {
              public void AddPersonAutoMapper(Person person)
              {
                  using (var dbContext = new PersonDbContext())
                  {
                      dbContext.People.Add(Mapper.Map<PersonRow>(person));
                      dbContext.SaveChanges();
                  }
              }
      
              public List<Person> FindAutoMapper(string lastName)
              {
                  using (var dbContext = new PersonDbContext())
                  {
                      var foundPeopleFromDb = dbContext.People.Where(p => p.LName == lastName).ToList();
                      return foundPeopleFromDb.Select(Mapper.Map<Person>).ToList();
                  }
              }
          }
      }
      

    AutoMapper conclusion
    Something just isn’t right here. You have to call more complex code to get an object converted. The ReverseBack() method saves us from having to create the reverse copy manually. Still, there are two methods and three lambda’s per property to copy. Hardly saving code or making life easier.

    The configuration code looks way more complex than the extension method code. I had a bug in my mapper config, and I couldn’t see it because the code is so busy.

    The AutoMapper code also isn’t intuitive. The methods aren’t obvious and it is not clear what it is doing without reading the documentation. Mapper.Map(p) doesn’t not clearly tell me that I am converting from an object of type Person to an object of type PersonRow. To me a Map is a HashTable or a Dictionary. I assume at first glance, that I am calling some type of Dictionary. The syntax breaks the “code should be clear” and the “code should be self documenting” rules. Any developer not familiar with AutoMapper will have no idea what your code is doing.

    Note: AutoMapper supposedly adds a feature that allows for a copy if the properties are the same with just one line of code: Mapper.CreateMap();

    I can see how if you had a lot of objects with identical properties that AutoMapper would be tempting. Still, the naming and lack of readability gets to me. Mapping.Map(p) just isn’t clear. If all the properties of all the objects match, scripting a clear, self-documenting extension method pre-build would be the way to go. We need a pre-build solution, not a runtime solution.

    If a field is added and named the same, nothing has to be done and AutoMapper works. However, if the fields are named differently, then you still have to add it to the Mapper config.

    Implicit Casts

    You could do this with Implicit casts.

    1. Add an implicit cast tot he object under your control, Person.
      using System;
      using System.Runtime.Serialization;
      using WcfToEntityAutomapperExample.DAL.Model;
      
      namespace WcfToEntityAutomapperExample.Services.Model
      {
          [DataContract]
          public class Person
          {
              [DataMember]
              public string FirstName { get; set; }
              [DataMember]
              public string MiddleName { get; set; }
              [DataMember]
              public string LastName { get; set; }
              [DataMember]
              public DateTime DateOfBirth { get; set; }
              [DataMember]
              public DateTime? DateOfDeath { get; set; }
      
              // User-defined conversion from Digit to double 
              public static implicit operator Person(PersonRow personRow)
              {
                  return new Person
                  {
                      FirstName = personRow.FName,
                      MiddleName = personRow.MName,
                      LastName = personRow.LName,
                      DateOfBirth = personRow.BD,
                      DateOfDeath = personRow.DD
                  };
              }
              //  User-defined conversion from double to Digit 
              public static implicit operator PersonRow(Person person)
              {
                  return new PersonRow
                  {
                      FName = person.FirstName,
                      MName = person.MiddleName,
                      LName = person.LastName,
                      BD = person.DateOfBirth,
                      DD = person.DateOfDeath
                  };
              }
          }
      }
      

      The implicit cast is not included in the client code so it is fine to add to the Person DataContract.

    2. Use it in your services.
      using System.Collections.Generic;
      using System.Linq;
      using AutoMapper;
      using WcfToEntityAutomapperExample.DAL;
      using WcfToEntityAutomapperExample.DAL.Model;
      using WcfToEntityAutomapperExample.Extensions;
      using WcfToEntityAutomapperExample.Services.Interfaces;
      using WcfToEntityAutomapperExample.Services.Model;
      
      namespace WcfToEntityAutomapperExample.Services
      {
          public class Service1 : IService1
          {
              public void AddPersonImplicitCast(Person person)
              {
                  using (var dbContext = new PersonDbContext())
                  {
                      dbContext.People.Add(person);
                      dbContext.SaveChanges();
                  }
              }
      
              public List<Person> FindImplicitCast(string lastName)
              {
                  using (var dbContext = new PersonDbContext())
                  {
                      var foundPeopleFromDb = dbContext.People.Where(p => p.LName == lastName).ToList();
                      return foundPeopleFromDb.Select(p => (Person)p).ToList();
                  }
              }
          }
      }
      

    Implicit Cast Conclusion

    Implicit Cast was pretty simple. I didn’t need any other classes. However, it muddied up a DataContract model class.

    It is not obvious why you can add a Person where a PersonRow is needed, but it makes sense.

    If I add a property or field, I’d have to add it to the cast.

    My Winner

    To me it is the extension method, with implicit casts a close second. I just like the simplicity of the code. A first year developer can understand and use it. I also like that it doesn’t muddy up the Model object iself like implicit operators do. Nor does it require me to create a mapping config, and initialize the mapping config.

    A read a unit testing argument that unit tests won’t fail when a field is added. I had to disagree. I can put refection code in my unity test fail a test if a property is not copied. Now the reflection code is in a test project not in the production project.

    My Loser

    AutoMapper. It just doesn’t add the simplicity that it claims to. It by far the most complex in this scenario. Complexity != better. The gains of auto mapping Properties and Fields with the same name doesn’t outweigh the losses in readability.

    Also, extension methods are far faster than AutoMapper. I didn’t do benchmarks but 7 times is what other have found. I have some data sets that take a couple of seconds to return. Times a couple of seconds by 7 and you will quickly see that such performance matters. The cost to use reflection when looping through can’t be good for you.

    Also, I don’t buy into the argument that performance doesn’t matter. Performance issues pile up over time. I agree that you should not write unreadable code to optimize before you know know that readable code performs poorly. However, if two pieces of code are clear and readable and one is more performant, use the more performant. You shouldn’t make your code more complex and harder to understand to get unnecessary optimization. But with AutoMapper, you are making your code more complex and harder to understand to get less performance? How does that make sense?

    Script the creation of the extension methods for objects with members named the same. You’ll be better off for it. You could even add the script to a pre-build command so the extension method is updated pre-build whenever a property is added.

    Please comment and tell me which is your winner vs loser?

    Logging an Xml SOAP Request from a C# client before sending it

    OK. So I wanted to log the xml SOAP request from a C# client before the client actually sent it. The server is referenced using the Web Reference method with these steps:

    1. Right-click on References and select Add Service Reference…
    2. Click Advanced (bottom left of window)
    3. Click Add Web Reference… (bottom left of window)
    4. Enter the URL and click the arrow.
    5. Enter a namespace and click Add reference.

    So this is NOT a WCF client hitting a WCF service, so I can’t use a ClientMessageInspector. However, I needed a similar feature. The first option I found output the Xml to the Visual Studio output window, though the output wasn’t clean. Fortunately, I found a more ClientMessageInspector-like method thanks to this stackoverflow post. It seems there is a SoapExtension object I can inherit from. The example in the stackoverflow post was for a server, but it worked from the client as well.

    My steps:

    1. Create the project in Visual Studio.
    2. Add Log4Net from NuGet and add Log4Net settings in the Program.cs file.
    3. Add a WebRefence to the Service.
    4. Call the service in main().
      using log4net;
      using log4net.Appender;
      using log4net.Config;
      using log4net.Layout;
      using System.Reflection;
      using System.Text;
      using YourProject.Extensions;
      
      namespace YourProject
      {
          class Program
          {
              private static ILog Logger
              {
                  get { return _Logger ?? (_Logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType)); }
              } private static ILog _Logger;
      
              static void Main(string[] args)
              {
                  ConfigureLog4Net();
                  CallWebService();
              }
      
              private static void CallWebService()
              {
                 // call service here
              }
      
              private static void ConfigureLog4Net()
              {
                  var appender = new FileAppender()
                  {
                      Layout = new SimpleLayout(),
                      File = Assembly.GetExecutingAssembly().Location + ".log",
                      Encoding = Encoding.UTF8,
                      AppendToFile = true,
                      LockingModel = new FileAppender.MinimalLock()
                  };
                  appender.ActivateOptions();
                  BasicConfigurator.Configure(appender);
              }
          }
      }
      
    5. Add my Xml helper class so we can log the SOAP Xml with Pretty Xml. See this post: An Xml class to linearize xml, make pretty xml, and encoding in UTF-8 or UTF-16.
    6. Add the SoapLoggerExtension : SoapExtension class.
      using System;
      using System.IO;
      using System.Reflection;
      using System.Web.Services.Protocols;
      using log4net;
      
      namespace YourProject.Extensions
      {
          public class SoapLoggerExtension : SoapExtension
          {
              private static ILog Logger
              {
                  get { return _Logger ?? (_Logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType)); }
              } private static ILog _Logger;
      
              private Stream _OldStream;
              private Stream _NewStream;
      
              public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute)
              {
                  return null;
              }
      
              public override object GetInitializer(Type serviceType)
              {
                  return null;
              }
      
              public override void Initialize(object initializer)
              {
      
              }
      
              public override Stream ChainStream(Stream stream)
              {
                  _OldStream = stream;
                  _NewStream = new MemoryStream();
                  return _NewStream;
              }
      
              public override void ProcessMessage(SoapMessage message)
              {
                  switch (message.Stage)
                  {
                      case SoapMessageStage.BeforeSerialize:
                          break;
                      case SoapMessageStage.AfterSerialize:
                          Log(message, "AfterSerialize");
                          CopyStream(_NewStream, _OldStream);
                          _NewStream.Position = 0;
                          break;
                      case SoapMessageStage.BeforeDeserialize:
                          CopyStream(_OldStream, _NewStream);
                          Log(message, "BeforeDeserialize");
                          break;
                      case SoapMessageStage.AfterDeserialize:
                          break;
                  }
              }
      
              public void Log(SoapMessage message, string stage)
              {
                  _NewStream.Position = 0;
                  Logger.Debug(stage);
                  var reader = new StreamReader(_NewStream);
                  string requestXml = reader.ReadToEnd();
                  _NewStream.Position = 0;
                  if (!string.IsNullOrWhiteSpace(requestXml))
                      Logger.Debug(new Xml(requestXml).PrettyXml);
              }
      
              public void ReverseIncomingStream()
              {
                  ReverseStream(_NewStream);
              }
      
              public void ReverseOutgoingStream()
              {
                  ReverseStream(_NewStream);
              }
      
              public void ReverseStream(Stream stream)
              {
                  TextReader tr = new StreamReader(stream);
                  string str = tr.ReadToEnd();
                  char[] data = str.ToCharArray();
                  Array.Reverse(data);
                  string strReversed = new string(data);
      
                  TextWriter tw = new StreamWriter(stream);
                  stream.Position = 0;
                  tw.Write(strReversed);
                  tw.Flush();
              }
      
              private void CopyStream(Stream fromStream, Stream toStream)
              {
                  try
                  {
                      StreamReader sr = new StreamReader(fromStream);
                      StreamWriter sw = new StreamWriter(toStream);
                      sw.WriteLine(sr.ReadToEnd());
                      sw.Flush();
                  }
                  catch (Exception ex)
                  {
                      string message = String.Format("CopyStream failed because: {0}", ex.Message);
                      Logger.Error(message, ex);
                  }
              }
          }
      }
      
    7. Add a the Soap to the App.config.
      <configuration>
      
        <!-- Other stuff here -->
      
        <system.web>
          <webServices>
            <soapExtensionTypes>
              <add type="YourProject.Extensions.SoapLoggerExtension, YourProjectNamespace" priority="2" group="Low" />
            </soapExtensionTypes>
          </webServices>
        </system.web>
      </configuration>
      
    8. Now make your web service call and the SOAP xml will be logged to a file.

    Happy day.

    Authenticating to Java web services with C# using SOAP authentication

    Download ProjectWell, we did method 1, basic authentication in our last post: Authenticating to Java web services with C# using basic authentication (using FlexNet services as examples). Let’s do method 2 here.

    Method 2 – SOAP Authentication

    SOAP authentication is a bit tricky. We have to get to the SOAP request and add headers but we don’t have access to the SOAP header through our SOAP service clients. Once we have access, we need to create custom SoapHeader objects.

    We have to use a SoapExtension. A SoapExtension will apply to all SAOP requests, and we may not want that, so we need to enable it based on service.

    Step 1 – Create Custom SOAP Header objects for UserId and UserPassword

    I created a base object. Notice the XmlText attribute.

    using System.Web.Services.Protocols;
    using System.Xml.Serialization;
    
    namespace ConnectToFlexeraExample.Model
    {
        public class BaseSoapHeader : SoapHeader
        {
            public BaseSoapHeader()
            {
                Actor = "http://schemas.xmlsoap.org/soap/actor/next";
                MustUnderstand = false;
            }
    
            [XmlText]
            public virtual string Value { get; set; }
        }
    }
    

    Then a UserIdSoapHeader object. Notice the XmlRoot attribute.

    using System.Xml.Serialization;
    
    namespace ConnectToFlexeraExample.Model
    {
        [XmlRoot("UserId", Namespace = "urn:com.macrovision:flexnet/platform")]
        public class UserIdSoapHeader : BaseSoapHeader
        {
    
        }
    }
    
    using System;
    using System.Text;
    using System.Xml.Serialization;
    
    namespace ConnectToFlexeraExample.Model
    {
        [XmlRoot("UserPassword", Namespace = "urn:com.macrovision:flexnet/platform")]
        public class PasswordSoapHeader : BaseSoapHeader
        {
            [XmlIgnore]
            public string EncodedPassword
            {
                set { Value = Convert.ToBase64String(Encoding.UTF8.GetBytes(value)); }
            }
        }
    }
    

    Step 2 – Add a SoapHeaderInjectionExtension : SoapExtension

    using ConnectToFlexeraExample.Model;
    using System;
    using System.Collections.Generic;
    using System.Net;
    using System.Web.Services.Protocols;
    
    namespace ConnectToFlexeraExample.Extensions
    {
        public class SoapHeaderInjectionExtension : SoapExtension
        {
            public static Dictionary<string, bool> EnabledServices = new Dictionary<string, bool>();
            public static Dictionary<string, NetworkCredential> UserAndPassword = new Dictionary<string, NetworkCredential>();
    
            public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute)
            {
                return null; // Unused
            }
    
            public override object GetInitializer(Type serviceType)
            {
                return null; // Unused
            }
    
            public override void Initialize(object initializer)
            {
                // Unused
            }
    
            public override void ProcessMessage(SoapMessage message)
            {
                if (!IsEnabledForUrl(message.Url))
                    return;
                switch (message.Stage)
                {
                    case SoapMessageStage.BeforeSerialize:
                        NetworkCredential creds;
                        if (UserAndPassword.TryGetValue(message.Url, out creds))
                        {
                            message.Headers.Add(new UserIdSoapHeader { Value = creds.UserName });
                            message.Headers.Add(new PasswordSoapHeader { EncodedPassword = creds.Password });
                        }
                        break;
                    case SoapMessageStage.AfterSerialize:
                        break;
                    case SoapMessageStage.BeforeDeserialize:
                        break;
                    case SoapMessageStage.AfterDeserialize:
                        break;
                }
            }
    
            public bool IsEnabledForUrl(string url)
            {
                bool isEnabled;
                EnabledServices.TryGetValue(url, out isEnabled);
                return isEnabled;
            }
        }
    }
    

    Step 3 – Add the SoapExtension to the .config

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
    
      <!-- Other stuff -->
    
      <system.web>
        <webServices>
          <soapExtensionTypes>
            <add type="ConnectToFlexeraExample.Extensions.SoapHeaderInjectionExtension, ConnectToFlexeraExample" priority="1" group="High" />
            <add type="ConnectToFlexeraExample.Extensions.SoapLoggerExtension, ConnectToFlexeraExample" priority="2" group="Low" />
          </soapExtensionTypes>
        </webServices>
      </system.web>
    </configuration>
    

    Step 4 – Update SetNetworkCredentials extension method

    We now want this method to accept either SOAP or Basic auth. We are going to key off of PreAuthenticate.

        public static class WebClientProtocolExtensions
        {
            public static void SetNetworkCredentials(this WebClientProtocol client, string username, string password, string customUrl = null, bool preAuthenticate = true)
            {
                client.PreAuthenticate = preAuthenticate;
                client.Url = string.IsNullOrWhiteSpace(customUrl) ? client.Url : customUrl;
                var netCredential = new NetworkCredential(username, password);
                if (preAuthenticate)
                {
                    ICredentials credentials = netCredential.GetCredential(new Uri(client.Url), "Basic");
                    client.Credentials = credentials;
                }
                else
                {
                    SoapHeaderInjectionExtension.EnabledServices[client.Url] = true;
                    SoapHeaderInjectionExtension.UserAndPassword[client.Url] = netCredential;
                }
            }
        }
    

    Step 5 – Use the new service clients with SOAP

        private static void TestAuthenticationService(string user, string pass)
        {
            // Basic Auth Method
            // authenticationServiceClient.SetNetworkCredentials(user, pass);
            // Soap Auth Method
            authenticationServiceClient.SetNetworkCredentials(user, pass, null, false);
            var userInputType = new AuthenticateUserInputType
            {
                userName = user,
                password = pass,
                domainName = "FLEXnet"
            };
            var result = authenticationServiceClient.authenticateUser(userInputType);
            Logger.Info(result.Success);
        }
    

    And you are autenticating to Flexera SOAP-based java web services using C#!