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
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#
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
<?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
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.