Some time ago, I’ve written this post about sending parametrized emails with C#. After some time, the emails weren’t arriving to their destination and I didn’t know why that happened – there was no message and the program was out in production, so I didn’t have an easy way to debug it.

Then, I went to the oracle that knows everything and asked “what is the easiest way to debug a C# program that sends emails in production?”. The oracle answered: “go to this page and you will find the answers you are looking for”. Once again, it was right.

Yes, the post pointed me to the easiest way to add debugging to your app that sends emails. There is not even the need to change the app. Just add a new clause to your app.config file and that’s it. Your app will generate a log file with all the data sent and received. The clause to add is system.diagnostics and you should add the traces you want and send them to a listener:

<system.diagnostics>
  <trace autoflush="true" />
  <sources>
    <source name="System.Net" >
      <listeners>
        <add name="MyTraceFile"/>
      </listeners>
    </source>
    <source name="System.Net.Sockets">
      <listeners>
        <add name="MyTraceFile"/>
      </listeners>
    </source>
  </sources>
  <sharedListeners>
    <add  name="MyTraceFile" type="System.Diagnostics.TextWriterTraceListener" 
          initializeData="System.Net.trace.log"   />
  </sharedListeners>
  <switches>
    <add name="System.Net" value="Verbose" />
    <add name="System.Net.Sockets" value="Verbose" />
  </switches>
</system.diagnostics>

The clause above will trace all calls to System.Net and System.Net.Sockets, with a Verbose level, to a file named System,Net.trace.log.

You can change the level of the tracing to something less verbose, but one note here: if you try to use the Info level, as stated here you will get an error. You should use the Information level. Using the number levels don’t show an error, but don’t generate a log either. So, you should use the named levels.

After that, I could see the logs and notice what has happened:

System.Net Error: 0 : [22720] Exception in SmtpClient#58328727::Send - The SMTP server requires a secure connection or the client was not authenticated. The server response was: 5.5.1 Authentication Required. Learn more at.
   at System.Net.Mail.MailCommand.CheckResponse(SmtpStatusCode statusCode, String response)
   at System.Net.Mail.MailCommand.Send(SmtpConnection conn, Byte[] command, MailAddress from, Boolean allowUnicode)
   at System.Net.Mail.SmtpTransport.SendMail(MailAddress sender, MailAddressCollection recipients, String deliveryNotify, Boolean allowUnicode, SmtpFailedRecipientException& exception)
   at System.Net.Mail.SmtpClient.Send(MailMessage message)
System.Net.Sockets Verbose: 0 : [22720] Entering Socket#24827179::Dispose()
System.Net Error: 0 : [22720] Exception in AppDomain#41560081::UnhandledExceptionHandler - The SMTP server requires a secure connection or the client was not authenticated. The server response was: 5.5.1 Authentication Required. Learn more at.
   at System.Net.Mail.MailCommand.CheckResponse(SmtpStatusCode statusCode, String response)
   at System.Net.Mail.MailCommand.Send(SmtpConnection conn, Byte[] command, MailAddress from, Boolean allowUnicode)
   at System.Net.Mail.SmtpTransport.SendMail(MailAddress sender, MailAddressCollection recipients, String deliveryNotify, Boolean allowUnicode, SmtpFailedRecipientException& exception)
   at System.Net.Mail.SmtpClient.Send(MailMessage message)
   at HtmlEmail.Program.Main(String[] args) in D:\Documentos\Artigos\Artigos\CSharp\HtmlEmail\HtmlEmail\HtmlEmail\Program.cs:line 41

Just a change in the password!

Some time ago, I’ve written this post about loading XAML dynamically. You can use this in many different ways:

  • store the views in a database
  • load the views from a server
  • change views depending on the user

Using that method, you can change the view, but there is a pitfall: all code must be loaded when the code is initialized. To change anything, you must recompile all the code. That way, the Views you are loading must have properties that match the ones with the ViewModels already in the code.

So, I started to think a way to load the XAML files and its corresponding ViewModel dynamically. Fortunately, C# provides us a mechanism to compile C# code at runtime and execute it. That’s great for our needs.

Compiling C# code at runtime

Compiling code at runtime is not new, you can compile code using the CSharpCodeProvider class with some code like this one:

        static void Main(string[] args)
        {
            CSharpCodeProvider provider = new CSharpCodeProvider();
            CompilerParameters parameters = new CompilerParameters {GenerateInMemory = true};
            parameters.ReferencedAssemblies.Add("System.dll");
            var code =
@"  
using System;
namespace DynamicCompile
{
    public class DynamicCode
    {
        public void Execute()
        {
            Console.WriteLine(""Hello World"");
        }
    }
}";
            CompilerResults results = provider.CompileAssemblyFromSource(
                parameters, code);
            if (!results.Errors.HasErrors)
            {
                var type = results.CompiledAssembly.GetType("DynamicCompile.DynamicCode");
                var method = type.GetMethod("Execute", BindingFlags.Public | BindingFlags.Instance);
                var cls = Activator.CreateInstance(type);
                method?.Invoke(cls, null);
            }
            else
            {
                foreach (CompilerError error in results.Errors)
                {
                    Console.WriteLine(error.ErrorText);
                }
            }
        }

If you execute this code, you will see “Hello World” written in the console. To use it, you must add the namespaces System.CodeDom.Compiler and System. CSharp. This code will use the legacy compiler and will compile code before C#6. If you want to compile C#6 code or newer, you will have to use the Roslyn compiler. To do that, you must add the Microsoft.CodeDom.Providers.DotNetCompilerPlatform NuGet package and add the Microsoft.CodeDom.Providers.DotNetCompilerPlatform namespace. That way, the same code will be able to compile C#6 or later:

        static void Main(string[] args)
        {
            CSharpCodeProvider provider = new CSharpCodeProvider();
            CompilerParameters parameters = new CompilerParameters {GenerateInMemory = true};
            parameters.ReferencedAssemblies.Add("System.dll");
            var code =
@"  
using System;
namespace DynamicCompile
{
    public class DynamicCode
    {
        const string str = ""World"";
        public void Execute()
        {
            Console.WriteLine($""Hello {str}"");
        }
    }
}";
            CompilerResults results = provider.CompileAssemblyFromSource(
                parameters, code);
            if (!results.Errors.HasErrors)
            {
                var type = results.CompiledAssembly.GetType("DynamicCompile.DynamicCode");
                var method = type.GetMethod("Execute", BindingFlags.Public | BindingFlags.Instance);
                var cls = Activator.CreateInstance(type);
                method?.Invoke(cls, null);
            }
            else
            {
                foreach (CompilerError error in results.Errors)
                {
                    Console.WriteLine(error.ErrorText);
                }
            }
        }

As you can see, the code above gives the same result, but uses the string interpolation, available in C#6. With this knowledge, we can work on loading the ViewModel code at runtime.

Loading and Running the ViewModel code at runtime

We’ve seen how to compile and run some code at runtime. With this knowledge, we can create a loose file with the ViewModel corresponding to the loaded XAML, load it and compile it at runtime. One extra bonus is that the View doesn’t know where do the data comes from, so we can load the ViewModel, compile it, instantiate an instance of the compiled class and assign this instance as the DataContext for the View.

As a sample, we will create a simple WPF project that will load a XAML file and its ViewModel into the main screen. Create a new blank WPF project and call it DynamicXAMLAndVM. In the XAML for MainPage.xaml, add this code:

<Grid>
   <ContentControl x:Name="WndContent"/> 
</Grid>

In the code behind for MainPage.xaml.cs, add this code:

public MainWindow()
{
    InitializeComponent();
    using (FileStream fs = new FileStream("CustView.xaml", FileMode.Open))
    {
        WndContent.Content= XamlReader.Load(fs) as FrameworkElement;
        var vmType = LoadViewModel("CustViewModel");
        if (vmType == null)
            MessageBox.Show(_errors, "Errors in compile");
        else
            DataContext = Activator.CreateInstance(vmType);
    }
    
}

private string _errors;
public Type LoadViewModel(string viewModelName)
{
    CSharpCodeProvider provider = new CSharpCodeProvider();
    CompilerParameters parameters = new CompilerParameters {GenerateInMemory = true};
    parameters.ReferencedAssemblies.Add("System.dll");
    parameters.ReferencedAssemblies.Add(Assembly.GetEntryAssembly().Location);
    var code = File.ReadAllText(viewModelName + ".cs");
    CompilerResults results = provider.CompileAssemblyFromSource(parameters, code);
    if (results.Errors.HasErrors)
    {
        _errors = "";
        foreach (CompilerError error in results.Errors)
        {
            _errors += $"Error #{error.ErrorNumber}: {error.ErrorText}\n";
        }

        return null;
    }
    else
    {
        Assembly assembly = results.CompiledAssembly;
        return assembly.GetType($"DynamicXamlAndVM.{viewModelName}");
    }
}

In the constructor, we load the XAML file and assign it to the Content property of the ContentControl. Then we call LoadViewModel, that will load the ViewModel and return its type. If the type is not null, we create an instance of the class with Activator.CreateInstance and assign it to the DataContext of the View. That’s all that’s needed to load the XAML and the ViewModel.

LoadViewModel will create a CSharpCodeProvider and will compile the code. If there are no errors in the code, it will return the parsed type. There is something that should be noticed here: we are referencing two assemblies for the compilation: System.dll and the current assembly. I’m doing that because the compiled class will be located in a separate assembly and won’t have access to the code in the current one.

I am not using any MVVM framework. Instead, I have created a new class, RelayCommand, based on Josh Smith’s code found here.

public class RelayCommand : ICommand
{
    private readonly Predicate<object> _canExecute;
    private readonly Action<object> _execute;

    public RelayCommand(Action<object> execute, Predicate<object> canExecute)
    {
        _canExecute = canExecute;
        _execute = execute;
    }

    public event EventHandler CanExecuteChanged
    {
        add => CommandManager.RequerySuggested += value;
        remove => CommandManager.RequerySuggested -= value;
    }

    public bool CanExecute(object parameter)
    {
        return _canExecute(parameter);
    }

    public void Execute(object parameter)
    {
        _execute(parameter);
    }
}

To access this code in the main assembly, you must add it to the Referenced Assemblies. If you are using a third party MVVM framework, you must add all its assemblies to the referenced assemblies.

The next step is to create the View and the ViewModel. Create a new file and name it CustView.xaml. In the properties page, set its BuildAction to None and the Copy to output directory to Copy if newer. Then, add this code:

<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
    <Grid.RowDefinitions>
        <RowDefinition Height="40"/>
        <RowDefinition Height="40"/>
        <RowDefinition Height="40"/>
        <RowDefinition Height="40"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="2*"/>
    </Grid.ColumnDefinitions>
    <TextBlock Grid.Column="0" Grid.Row="0" Text="ID" Margin="5"/>
    <TextBlock Grid.Column="0" Grid.Row="1" Text="Name" Margin="5"/>
    <TextBlock Grid.Column="0" Grid.Row="2" Text="Address" Margin="5"/>
    <TextBlock Grid.Column="0" Grid.Row="3" Text="City" Margin="5"/>
    <TextBox Grid.Column="1" Grid.Row="0" Text="{Binding ID}" Margin="5"/>
    <TextBox Grid.Column="1" Grid.Row="1" Text="{Binding Name}" Margin="5"/>
    <TextBox Grid.Column="1" Grid.Row="2" Text="{Binding Address}" Margin="5"/>
    <TextBox Grid.Column="1" Grid.Row="3" Text="{Binding City}" Margin="5"/>
    <Button Grid.Column="1" Grid.Row="4" Command="{Binding ClearCommand}" Margin="5" 
            HorizontalAlignment="Right" VerticalAlignment="Bottom" Content="Clear Data"
            Width="65" Height="35" />
</Grid>

As you can see, it’s a simple grid with some TextBoxes and a Button. The Text property of the TextBoxes are bound to properties in the DataContext. Thanks to the data binding, the View does not know from where the data comes from. We just need to assign a class that has the properties ID, Name, Address, City and a command named ClearCommand. The ViewModel is also a loose cs file. Create a new file and name it CustViewModel.cs, setting its BuildAction to None and the Copy to output directory to Copy if newer. Then, add this code:

class CustViewModel : INotifyPropertyChanged
{
    private string _id;
    private string _name;
    private string _address;
    private string _city;
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = nul
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    public CustViewModel()
    {
        ID = "007";
        Name = "James Bond";
        Address = "MI6";
        City = "London";

    }
    public string ID
    {
        get => _id;
        set
        {
            _id = value;
            OnPropertyChanged();
        }
    }

    public string Name
    {
        get => _name;
        set
        {
            _name = value;
            OnPropertyChanged();
        }
    }

    public string Address
    {
        get => _address;
        set
        {
            _address = value;
            OnPropertyChanged();
        }
    }

    public string City
    {
        get => _city;
        set
        {
            _city = value;
            OnPropertyChanged();
        }
    }

    public ICommand ClearCommand => new RelayCommand(
        o =>
        {
            ID = "";
            Name = "";
            Address = "";
            City = "";
        },
        o => true);
}

This is a simple ViewModel, which has the properties needed for the View and a command that will clear all bound properties when it’s executed. That’s all that is needed to load a View with its ViewModel and add it to the main screen. When you run the app, you will see something like this:

As you can see, all the data is loaded into the TextBoxes and, when you click on the button, the data is cleared. Nice, no? This code is tied to the files in the project. Now, we can streamline this process, refactoring the code and allowing it to call any file added in the project. For that, we will use some rules:

  • All the views will be in he Views folder
  • All the viewmodels will be in the ViewModels folder and will have the same name of the View
  • The namespace for all viewmodels will be DynamicVM

Refactoring the code

In the project, create a new folder and name it Views and move the CustView.xaml file to it. Rename the file to Cust.xaml. Then, create a new folder and name it ViewModels and move the CustViewModel.cs file to it. Rename it to Cust.cs. In the file, rename the class to Cust and rename the namespace to DynamicVM.

Create a new class named DynamicContentLoader and add this code:

using System;
using System.CodeDom.Compiler;
using System.IO;
using System.Reflection;
using System.Windows;
using System.Windows.Markup;
using Microsoft.CodeDom.Providers.DotNetCompilerPlatform;

namespace DynamicXamlAndVMRefactored
{
    public class DynamicContentLoader
    {
        public static string Errors => _errors;
        public static FrameworkElement Load(string viewName)
        {
            var viewPath = $"Views\\{viewName}.xaml";
            if (!File.Exists(viewPath))
                return null;
            try
            {
                using (FileStream fs = new FileStream(viewPath, FileMode.Open))
                {
                    var result = XamlReader.Load(fs) as FrameworkElement;
                    if (result == null)
                        return null;
                    var viewModelPath = $"ViewModels\\{viewName}.cs";
                    if (File.Exists(viewModelPath))
                    {
                        var vmType = LoadViewModel(viewModelPath, viewName);
                        if (vmType != null)
                        {
                            result.DataContext = Activator.CreateInstance(vmType);
                        }
                    }

                    return result;
                }
            }
            catch (Exception e)
            {
                _errors = e.Message;
                return null;
            }
            
        }

        private static string _errors;
        private static Type LoadViewModel(string viewModelName, string viewName)
        {
            CSharpCodeProvider provider = new CSharpCodeProvider();
            CompilerParameters parameters = new CompilerParameters { GenerateInMemory = true };
            parameters.ReferencedAssemblies.Add("System.dll");
            parameters.ReferencedAssemblies.Add(Assembly.GetEntryAssembly().Location);
            var code = File.ReadAllText(viewModelName);
            CompilerResults results = provider.CompileAssemblyFromSource(parameters, code);
            if (results.Errors.HasErrors)
            {
                _errors = "";
                foreach (CompilerError error in results.Errors)
                {
                    _errors += $"Error #{error.ErrorNumber}: {error.ErrorText}\n";
                }

                return null;
            }
            else
            {
                Assembly assembly = results.CompiledAssembly;
                return assembly.GetType($"DynamicVM.{viewName}");
            }
        }
    }
}

This code is very similar to the previous one, we’ve created a class with a static method Load, that loads a XAML file and, if there is a corresponding ViewModel, loads it and assigns it as the DataContext for the view. That way, the code in MainWindow.xaml.cs is simplified:

public MainWindow()
{
    InitializeComponent();
    var content = DynamicContentLoader.Load("Cust");
    if (DynamicContentLoader.Errors != null)
        MessageBox.Show(DynamicContentLoader.Errors, "Errors in compile");
    WndContent.Content = content;
}

Running the program, you will have the same result as the previous run.

Conclusions

As you’ve seen, if you want to have dynamic views, you are not limited to use codeless windows. You can also add code for it, compile it on the fly and use it tied to the view, thanks to the magic of data binding. That way, you can create applications fully dynamic, that can be easily updated whenever you want, with no need of recompilation and redeploy.

All the source code for this article is at https://github.com/bsonnino/DynamicXamlAndVM