Useful C# Snippets

Some useful snippets collected during my work with C#, UWP, and .NET.

Load HTML from app into WebView

The HTML and other resources should be inside the Assets/web folder in the project, and the files should be marked as Content in the properties.

webView.Navigate(new System.Uri("ms-appx-web:///Assets/web/index.html"));

Read JSON from local resources

var json = File.ReadAllText("Assets/file.json");

Message box dialog

Of course the surrounding method should be async.

using Windows.UI.Popups;
var dialog = new MessageDialog(seat);
await dialog.ShowAsync();

C# Listen to file changes

Source:

using System;
using System.IO;
using System.Runtime.Loader;
using System.Threading.Tasks;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Primitives;

namespace CAL.Daemon
{
    class Program
    {
        static PhysicalFileProvider fileProvider = new PhysicalFileProvider(Directory.GetCurrentDirectory());

        static void Main(string[] args)
        {
            //register sigterm event handler
            AssemblyLoadContext.Default.Unloading += SigTermEventHandler;

            //register sigint event handler
            Console.CancelKeyPress += CancelHandler;

            Console.WriteLine("Monitoring quotes.txt for changes (Ctrl-c to quit)...");

            while (true)
            {
                MainAsync().GetAwaiter().GetResult();
            }
        }

        static async Task MainAsync()
        {
            IChangeToken token = fileProvider.Watch("quotes.txt");
            TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();

            token.RegisterChangeCallback(state =>
            {
                var info = fileProvider.GetFileInfo("quotes.txt");
                var date = info.LastModified;
                var length = info.Length;
                Console.WriteLine($"last modified: { date} ({ length})");
                ((TaskCompletionSource<object>)state).TrySetResult(null);
            } , tcs);

            await tcs.Task.ConfigureAwait(false);

            Console.WriteLine("quotes.txt changed");
        }

        static void SigTermEventHandler(AssemblyLoadContext obj)
        {
            Console.WriteLine("Unloading...");
        }

        static void CancelHandler(object sender, ConsoleCancelEventArgs e)
        {
            Console.WriteLine("Exiting...");
        }
    }
}

Lock multithreaded access to method

For example to avoid several threads writing the same contents to the same file.

private static readonly object locker = new object();

lock (locker)
{
    string text;
    using (var stream = new MemoryStream())
    {
        var s = new DataContractJsonSerializer(typeof(Cls));
        s.WriteObject(stream, obj);
        text = Encoding.UTF8.GetString(stream.ToArray());
    }
    File.WriteAllText(file.Path, text);
}

Invoke JavaScript on WebView

The interface for InvokeScriptAsync() takes only strings and returns only strings. Of course the surrounding method should be async.

var message = "something";
string[] data = { message };
await webView.InvokeScriptAsync("js_function_name", data);

Deep cloning in C#

Source:

public interface IDeepCloneable
{
    object DeepClone();
}

public interface IDeepCloneable<T> : IDeepCloneable
{
    T DeepClone();
}

public class SampleClass : IDeepCloneable<SampleClass>
{
    public SampleClass DeepClone()
    {
        // Deep clone your object
        return ...;
    }

    object IDeepCloneable.DeepClone()
    {
        return this.DeepClone();
    }
}

Generating XML file using XSD file

Source:

<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="MyClass">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="Field1"
                    type="xs:string"/>
        <xs:element name="Field2"
                    type="xs:string"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

You can use this even on Mac:

xsd.exe /classes Test.xsd

using System.Xml.Serialization;
// ...
var data = new MyClass { Field1 = "test1", Field2 = "test2" };
var serializer = new XmlSerializer(typeof(MyClass));
using (var stream = new StreamWriter("C:\\test.xml"))
    serializer.Serialize(stream, data);

Result:

<?xml version="1.0" encoding="utf-8"?>
<MyClass xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <Field1>test1</Field1>
  <Field2>test2</Field2>
</MyClass>

Deserializing XML into objects

XmlSerializer serializer = new XmlSerializer(typeof(SegmentSeatMap));
string xml = File.ReadAllText("file.xml");

SegmentSeatMap seatmap = null;
using (TextReader r = new StringReader(xml))
{
    seatmap = (SegmentSeatMap)serializer.Deserialize(r);
}

Another option

XmlSerializer serializer = new XmlSerializer(typeof(SegmentSeatMap));
string path = "file.xml";
FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);
SegmentSeatMap obj = (SegmentSeatMap)serializer.Deserialize(fs);

More advanced, when the classes to deserialize are marked as [DataContract]

string xml = File.ReadAllText("file.xml");
DataContractSerializer serializer = new DataContractSerializer(typeof(SegmentSeatMap));
SegmentSeatMap obj = null;
using (XmlReader r = XmlReader.Create(new StringReader(xml)))
{
    obj = (SegmentSeatMap)serializer.ReadObject(r);
}

Reading the SOAP message

// Adapted from
// https://stackoverflow.com/a/43901543/133764
Message m = Message.CreateMessage(XmlReader.Create(path), int.MaxValue, MessageVersion.Soap11);
SoapReflectionImporter importer = new SoapReflectionImporter(new SoapAttributeOverrides(), "http://www.swiss.com/MD4C/Common");
XmlTypeMapping mapp = importer.ImportTypeMapping(typeof(ResponseBase));
XmlSerializer xmlSerializer = new XmlSerializer(mapp);
XmlDictionaryReader reader = m.GetReaderAtBodyContents();
ResponseBase obj = (ResponseBase)xmlSerializer.Deserialize(reader);
return obj;

C# Dynamic Object Created at Runtime

Source:

public class DynamicClass : DynamicObject
{
    private Dictionary<string, KeyValuePair<Type, object>> _fields;

    public DynamicClass(List<Field> fields)
    {
        _fields = new Dictionary<string, KeyValuePair<Type, object>>();
        fields.ForEach(x => _fields.Add(x.FieldName,
            new KeyValuePair<Type, object>(x.FieldType, null)));
    }

    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        if (_fields.ContainsKey(binder.Name))
        {
            var type = _fields[binder.Name].Key;
            if (value.GetType() == type)
            {
                _fields[binder.Name] = new KeyValuePair<Type, object>(type, value);
                return true;
            }
            else throw new Exception("Value " + value + " is not of type " + type.Name);
        }
        return false;
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        result = _fields[binder.Name].Value;
        return true;
    }
}

public class Field
{
    public Field(string name, Type type)
    {
        this.FieldName = name;
        this.FieldType = type;
    }

    public string FieldName;

    public Type FieldType;
}

var fields = new List<Field>() {
    new Field("EmployeeID", typeof(int)),
    new Field("EmployeeName", typeof(string)),
    new Field("Designation", typeof(string))
};

dynamic obj = new DynamicClass(fields);

//set
obj.EmployeeID = 123456;
obj.EmployeeName = "John";
obj.Designation = "Tech Lead";

obj.Age = 25;             //Exception: DynamicClass does not contain a definition for 'Age'
obj.EmployeeName = 666;   //Exception: Value 666 is not of type String

//get
Console.WriteLine(obj.EmployeeID);     //123456
Console.WriteLine(obj.EmployeeName);   //John
Console.WriteLine(obj.Designation);    //Tech Lead

XmlSerializer UTF-8

By default, the StringReader class processes everything as UTF-16; to do it in UTF-8, use this subclass:

c# - Serializing an object as UTF-8 XML in .NET - Stack Overflow

public class Utf8StringWriter : StringWriter
{
    public override Encoding Encoding => Encoding.UTF8;

    public Utf8StringWriter(StringBuilder str) : base(str){}
}

Use it like this:

var serializer = new XmlSerializer(typeof(ClassToSerialize));
var str = new StringBuilder();
using (var stream = new Utf8StringWriter(str))
{
    using (var xmlWriter = XmlWriter.Create(stream, new XmlWriterSettings { Indent = false }))
    {
        serializer.Serialize(xmlWriter, data);
    }
}
Console.WriteLine(str.Replace("\"", "\\\""));

Note the Indent = false to configure yet another factor of the final XML.