XML Serialization Helpers

public static class Serialization {
    private static readonly Encoding _defaultEncoding = Encoding.UTF8;

    public static T DeserializeXmlFile<T>(string fileName) {
        if (!File.Exists(fileName))
            throw new FileNotFoundException();

        var serializer = new XmlSerializer(typeof(T));
        using (var xmlReader = new XmlTextReader(fileName)) {
            return (T)serializer.Deserialize(xmlReader);
        }
    }

    public static T Deserialize<T>(TextReader textReader) {
        if (textReader == null)
            throw new ArgumentNullException("textReader");

        var serializer = new XmlSerializer(typeof(T));
        return (T)(serializer.Deserialize(textReader));
    }

    public static T Deserialize<T>(string serializedObject) {
        if (string.IsNullOrEmpty(serializedObject))
            return default(T);

        var serializer = new XmlSerializer(typeof(T));
        using (var objectReader = new StringReader(serializedObject)) {
            return (T)serializer.Deserialize(objectReader);
        }
    }

    public static void SerializeToXmlFile<T>(T objectToSerialize, string fileName) {
        SerializeToXmlFile(objectToSerialize, fileName, _defaultEncoding);
    }

    public static void SerializeToXmlFile<T>(T objectToSerialize, string fileName, Encoding encoding) {
        var serializer = new XmlSerializer(typeof(T));
        using (var xmlWriter = new XmlTextWriter(fileName, encoding) { Formatting = Formatting.Indented, IndentChar = '\t', Indentation = 1 }) {
            serializer.Serialize(xmlWriter, objectToSerialize);
        }
    }

    public static string Serialize<T>(T objectToSerialize, bool includeXmlDeclaration, bool indent) {
        var serializer = new XmlSerializer(typeof(T));
        var sb = new StringBuilder(0x1000);

        XmlTextWriter xmlWriter =
            includeXmlDeclaration
            ? new XmlTextWriter(new StringWriter(sb))
            : new XmlTextWriterWithoutDeclaration(new StringWriter(sb));

        if (indent) {
            xmlWriter.Formatting = Formatting.Indented;
            xmlWriter.IndentChar = '\t';
            xmlWriter.Indentation = 1;
        }

        var namespaces = new XmlSerializerNamespaces();
        namespaces.Add(string.Empty, string.Empty);
        serializer.Serialize(xmlWriter, objectToSerialize, namespaces);
        return sb.ToString();
    }

    private class XmlTextWriterWithoutDeclaration
        : XmlTextWriter
    {
        public XmlTextWriterWithoutDeclaration(TextWriter w)
            : base(w)
        { }

        public override void WriteStartDocument() { }

        public override void WriteStartDocument(bool standalone) { }
    }
}

These are just a few helpers to make using the built-in XmlSerializer a little bit easier. It skips the needless XML namespaces, which just ugly up simple XML. If you want to skip the <?xml version="1.0" encoding="utf-16"?> declaration, then you can use that overload.

[Serializable] public class Foo { public string Name { get; set; } public int Age { get; set; }

var foo = new Foo { Name = "john", Age = 34 };
string xml = Serialization.Serialize(foo, true, false); // Keep declaration
Console.WriteLine(xml);
Console.WriteLine();
xml = Serialization.Serialize(foo, false, false); // Remove declaration
Console.WriteLine(xml);
Console.WriteLine();
using (var writer = new StringWriter())
{
    new XmlSerializer(typeof(Foo)).Serialize(writer, foo); // Default serialization
    Console.WriteLine(writer.ToString());
}

Output:

<?xml version="1.0" encoding="utf-16"?><Foo><Name>john</Name><Age>34</Age></Foo>

<Foo><Name>john</Name><Age>34</Age></Foo>

<?xml version="1.0" encoding="utf-16"?>
<Foo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Name>john</Name>
  <Age>34</Age>
</Foo>

Windows Services with .NET Framework

This code demonstrates two simple techniques for Windows services in .NET. First, it shows how to create a Console application which also can be installed as a Windows service – this way you can write a Windows service and easily test and debug it without installing it, and without using multiple projects. Second, it shows how to set the service name at install-time instead of compile-time.

Create the project as a Console application, rather than a Windows service. Then just add the following code, and organize your codebase as you wish.

using System;
using System.ComponentModel;
using System.Configuration.Install;
using System.Linq;
using System.ServiceProcess;

namespace ConsoleApp1 {
    public partial class Service1 : ServiceBase {
        static void Main(string[] args) {
            var service = new Service1();
            if (Environment.UserInteractive) {
                try {
                    service.OnStart(args);
                } catch (Exception ex) {
                    Console.WriteLine(ex);
                } finally {
                    Console.WriteLine("DONE - Press <ENTER> to exit.");
                    service.OnStop();
                    Console.ReadLine();
                }
            } else {
                Run(service);
            }
        }

        protected override void OnStart(string[] args) { /* implementation */ }
        protected override void OnStop(){ /* implementation */ }
    }

    [RunInstaller(true)]
    public partial class ProjectInstaller : Installer {
        public ProjectInstaller() {
            string[] commandlineArgs = Environment.GetCommandLineArgs();

            string servicename;
            string servicedisplayname;
            ParseServiceNameSwitches(commandlineArgs, out servicename, out servicedisplayname);

            _serviceProcessInstaller = new ServiceProcessInstaller();
            _serviceInstaller = new ServiceInstaller();

            _serviceInstaller.ServiceName = servicename;
            _serviceInstaller.DisplayName = servicedisplayname;

            Installers.AddRange(new Installer[] { _serviceProcessInstaller, _serviceInstaller });
        }

        private ServiceProcessInstaller _serviceProcessInstaller;
        private ServiceInstaller _serviceInstaller;

        private void SetServicePropertiesFromCommandLine(ServiceInstaller serviceInstaller) {
            string[] commandlineArgs = Environment.GetCommandLineArgs();

            string servicename;
            string servicedisplayname;
            ParseServiceNameSwitches(commandlineArgs, out servicename, out servicedisplayname);

            serviceInstaller.ServiceName = servicename;
            serviceInstaller.DisplayName = servicedisplayname;
        }

        // http://www.runeibsen.dk/?p=153
        private void ParseServiceNameSwitches(string[] args, out string name, out string displayName) {
            var nameSwitch = args.FirstOrDefault(x => x.StartsWith("/servicename"));
            var displayNameSwitch = args.FirstOrDefault(x => x.StartsWith("/servicedisplayname"));

            if (nameSwitch == null)
                throw new ArgumentException("Argument 'servicename' is missing");
            if (displayNameSwitch == null)
                throw new ArgumentException("Argument 'servicedisplayname' is missing");
            if (!(nameSwitch.Contains('=') || nameSwitch.Split('=').Length < 2))
                throw new ArgumentNullException("The /servicename switch is malformed");

            if (!(displayNameSwitch.Contains('=') || displayNameSwitch.Split('=').Length < 2))
                throw new ArgumentNullException("The /servicedisplaynameswitch switch is malformed");

            name = nameSwitch.Split('=')[1];
            displayName = displayNameSwitch.Split('=')[1];

            name = name.Trim('"');
            displayName = displayName.Trim('"');
        }
    }
}

Installing it from the command line:

installutil -i /servicename="my service" /servicedisplayname="my display name" ConsoleApp1.exe

Versioned content in MVC

When you add a script or stylesheet to your HTML page, those requests can be cached by the browser, potentially providing outdated content to the browser.

If you’re not using a bundler or anything fancy like that, then the only way to prevent this problem is to create a brand new URL whenever your script file or stylesheet changes. This is easily accomplished with a querystring, so if your app was previously using app.js?v=1 and you change that to app.js?v=2, the browser will definitely not use the cached version, and will instead make a new request to the server, and pull the latest one.

Using the following technique, you can guarantee that you’ll always pull the latest script and stylesheet when working in dev, and when in production, you can define a “version key”, possibly in a config file or database, and if you ever update just the static content, you would only need to update that key, and it would force all browsers to pull new content.

public static class HtmlExtensions {
    private static string GetUniqueVersionKey() {
        #if DEBUG
        return Guid.NewGuid().ToString("N");
        #else
        // This needs to be somewhere you can get to it, like a web.config file or database
        return MvcApplication.GetUniqueVersionKey();
        #endif
    }

    public static MvcHtmlString Script(this HtmlHelper htmlHelper, string scriptFileName) {
        var urlHelper = new UrlHelper(htmlHelper.ViewContext.RequestContext);
        return new MvcHtmlString(string.Format("<script type=\"text/javascript\" src=\"{0}?uv={1}\"></script>",
            urlHelper.Content(scriptFileName), GetUniqueVersionKey()));
    }

    public static MvcHtmlString Style(this HtmlHelper htmlHelper, string styleFileName) {
        var urlHelper = new UrlHelper(htmlHelper.ViewContext.RequestContext);
        return new MvcHtmlString(string.Format("<link rel=\"stylesheet\" href=\"{0}?uv={1}\">",
            urlHelper.Content(styleFileName), GetUniqueVersionKey()));
    }
}

These will produce the appropriate link or script tag.

@Html.Style("app.css")
@Html.Script("app.js")

Simple Dependency Injection in .NET Core Console App

If you’re using ASP.NET Core, you get dependency injection out of the box. If you’re building a console app, you can get simple dependency injection with just a little bit of code.

For basic mapping, all you need is to create a ServiceProvider object that maps  your types, and your constructor injection works perfectly. Here’s a working sample:

// dotnet add package Microsoft.Extensions.DependencyInjection
class Program {

    // Map your items. Note that you can map a class to itself.
    private static ServiceProvider _serviceProvider = new ServiceCollection()
        .AddTransient<Program, Program>()
        .AddTransient<IManager, Manager>()
        .AddTransient<IRepository, Repository>()
        .BuildServiceProvider();

    // Uses the service provider to retrieve a Program instance and call Go()
    static void Main() => _serviceProvider.GetService<Program>().Go();

    // Constructor injection pulls in a Manager object
    private readonly IManager _manager;
    public Program(IManager manager) => _manager = manager;

    public void Go() => _manager.Go();
}

public interface IManager { void Go(); }

public class Manager : IManager {

    // Constructor injection pulls in a Repository object
    private readonly IRepository _repo;
    public Manager(IRepository repo) => _repo = repo;

    void IManager.Go() => Console.WriteLine(_repo.Hello("world"));
}

public interface IRepository { string Hello(string name); }

public class Repository : IRepository {
    string IRepository.Hello(string name) => $"Hello {name}";
}

Reference: https://andrewlock.net/using-dependency-injection-in-a-net-core-console-application/ 

Safe DataReader in .NET

If you’re using ADO.NET out of the box with a DataReader, null-checking is just a bit obnoxious. Normally in a real project, you’ll have a real framework around your data access, whether that’s Entity Framework, some third party tool, or your own home-grown repositories. But if you’re doing a small project and just using a DataReader, then at least do this much:

using System;
using System.Data;

namespace MyNameSpace {
    public class DataReaderEx {
        private readonly IDataReader _dataReader;

        public DataReaderEx(IDataReader dataReader) {
            _dataReader = dataReader;
        }
        public string GetString(string name) {
            int i = _dataReader.GetOrdinal(name);
            return _dataReader.IsDBNull(i) ? null : _dataReader.GetString(i);
        }
        public int GetInt32(string name) {
            int i = _dataReader.GetOrdinal(name);
            return _dataReader.IsDBNull(i) ? 0 : _dataReader.GetInt32(i);
        }
        public int? GetInt32Nullable(string name) {
            int i = _dataReader.GetOrdinal(name);
            return _dataReader.IsDBNull(i) ? (int?)null : _dataReader.GetInt32(i);
        }
        public long GetInt64(string name) {
            int i = _dataReader.GetOrdinal(name);
            return _dataReader.IsDBNull(i) ? 0 : _dataReader.GetInt64(i);
        }
        public long? GetInt64Nullable(string name) {
            int i = _dataReader.GetOrdinal(name);
            return _dataReader.IsDBNull(i) ? (long?)null : _dataReader.GetInt64(i);
        }
        public bool GetBoolean(string name) {
            int i = _dataReader.GetOrdinal(name);
            return !_dataReader.IsDBNull(i) && _dataReader.GetBoolean(i);
        }
        public bool? GetBooleanNullable(string name) {
            int i = _dataReader.GetOrdinal(name);
            return _dataReader.IsDBNull(i) ? (bool?)null : _dataReader.GetBoolean(i);
        }
        public DateTime GetDateTime(string name) {
            int i = _dataReader.GetOrdinal(name);
            return _dataReader.IsDBNull(i) ? DateTime.MinValue : _dataReader.GetDateTime(i);
        }
        public DateTime? GetDateTimeNullable(string name) {
            int i = _dataReader.GetOrdinal(name);
            return _dataReader.IsDBNull(i) ? (DateTime?)null : _dataReader.GetDateTime(i);
        }
        public Guid GetGuid(string name) {
            int i = _dataReader.GetOrdinal(name);
            return _dataReader.IsDBNull(i) ? Guid.Empty : _dataReader.GetGuid(i);
        }
        public Guid? GetGuidNullable(string name) {
            int i = _dataReader.GetOrdinal(name);
            return _dataReader.IsDBNull(i) ? (Guid?)null : _dataReader.GetGuid(i);
        }
    }
}

This gives you the ability to retrieve nullable values, and properly map them to null. It also converts nulls to the default value if you’re pulling a nullable column into a non-nullable variable.

// Old way:
int idx = rdr.GetOrdinal("Name");
string name = rdr.IsDBNull(idx) ? (string)null : rdr.GetString(idx);
idx = rdr.GetOrdinal("NumYears");
int numYears = rdr.IsDBNull(idx) ? 0 : rdr.GetInt32(idx);

// Alternative old way, but it just feels dirty:
string name = rdr["Name"] as string;
int numYears = (rdr["NumYears"] as int?) ?? 0;

// New way:
using (var rdr = comm.ExecuteReader()) {
   var rdrEx = new DataReaderEx(rdr);
   string name = rdrEx.GetString("Name");
   int numYears = rdrEx.GetInt32("NumYears");
}

Run .NET Windows app as Administrator

Sometimes you need to do adminstrative things from your Windows application. You can either force the user to “Run as Administrator”, which is annoying to the user, or you can kill this instance and restart it as admin programatically.

private void Go()
{
    WindowsPrincipal pricipal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
    bool hasAdministrativeRight = pricipal.IsInRole(WindowsBuiltInRole.Administrator);

    if (!hasAdministrativeRight)
    {
        RunElevated(Application.ExecutablePath);
        this.Close();
        Application.Exit();
    }
    
    // Do your administrator stuff
}

private static bool RunElevated(string fileName)
{
    ProcessStartInfo processInfo = new ProcessStartInfo();
    processInfo.Verb = "runas";
    processInfo.FileName = fileName;
    try
    {
        Process.Start(processInfo);
        return true;
    }
    catch (Win32Exception)
    {
        //Do nothing. Probably the user canceled the UAC window
    }
    return false;
}

Render view from controller in ASP.NET Core

In ASP.NET Core, if you want to render a view to a string, this Stack Overflow answer makes it simple. I’ve used this to return HTML in a JSON request that also includes other data, to build an email body, and to get raw HTML to pass off to wkhtmltopdf to build PDF from HTML.

public static async Task<string> RenderViewAsync<TModel>(this Controller controller, 
    string viewName, TModel model, bool partial = false) {
    if (string.IsNullOrEmpty(viewName)) {
        viewName = controller.ControllerContext.ActionDescriptor.ActionName;
    }

    controller.ViewData.Model = model;

    using (var writer = new StringWriter()) {
        IViewEngine viewEngine = controller.HttpContext.RequestServices
            .GetService(typeof(ICompositeViewEngine)) as ICompositeViewEngine;
        ViewEngineResult viewResult = viewEngine.FindView(
            controller.ControllerContext, viewName, !partial);

        if (viewResult.Success == false) {
            return $"A view with the name {viewName} could not be found";
        }

        ViewContext viewContext = new ViewContext(controller.ControllerContext,
            viewResult.View, controller.ViewData, controller.TempData,
            writer, new HtmlHelperOptions()
        );

        await viewResult.View.RenderAsync(viewContext);

        return writer.GetStringBuilder().ToString();
    }
}

Remove declaration and namespaces from XML serializer

Out of the box, .NET XML serialization is loaded with garbage that I personally never want. It’s one of the reasons I use JSON instead of XML whenever possible.

But one quick way to remove the junk, assuming you’re dealing with simple data, and don’t care about things like encoding or namespaces or whatever, is to just apply a few settings.

Given the following out-of-the-box code:

var foo = new Foo { Name = "John Doe", Age = 34 };
using (var writer = XmlWriter.Create(Console.Out)) {
    new XmlSerializer(typeof (Foo)).Serialize(writer, foo);
}

The console will see the following (aside from the indentation):

<?xml version="1.0" encoding="Codepage - 437"?>
<Foo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <Name>John Doe</Name>
    <Age>34</Age>
</Foo>

Add a little bit of configuration to the code, and you get something much nicer:

var ns = new XmlSerializerNamespaces(); ns.Add("", "");
var settings = new XmlWriterSettings { OmitXmlDeclaration = true };
using (var writer = XmlWriter.Create(Console.Out, settings)) {
    new XmlSerializer(typeof (Foo)).Serialize(writer, foo, ns); 
}
<Foo>
  <Name>John Doe</Name>
  <Age>34</Age>
</Foo>

JSON infinite loops in ASP.NET

If you accidentally (or purposely) have an infinite loop in an object, where it has a reference that points back to itself, when you try to return that object as JSON in ASP.NET, you get an error:

JsonSerializationException: Self referencing loop detected for property …

To avoid that, you can add a line to your Startup ConfigureServices method:

// dotnet add package Microsoft.AspNetCore.Mvc.NewtonsoftJson

services.AddNewtonsoftJson(options =>
    {
        options.SerializerSettings.ReferenceLoopHandling
            = ReferenceLoopHandling.Ignore;
    });

JSON casing in ASP.NET Core

Some mallethead decided that they wanted to take UpperCamelCase names of properties and change them to lowerCamelCase when sending JSON to the client. Sure, maybe this fits standard naming conventions, but it means that you’ll end up with different property names.

public JsonResult GetFoo()
{
    return Json(new Foo { 
        Name = "Jane Doe", 
        Age = 32 
    });
}

This returns the following content:

{"name":"Jane Doe","age":32}

Personally, I want the properties to match. Here’s the change to make that happen:

// dotnet add package Microsoft.AspNetCore.Mvc.NewtonsoftJson

// Startup.cs: in ConfigureServices
services.AddNewtonsoftJson(options =>
    {
        options.UseMemberCasing();
    });

Now the same code produces:

{"Name":"Jane Doe","Age":32}