<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[David Broadfoot]]></title><description><![CDATA[A software development blog from Sydney, Australia]]></description><link>https://www.davidbroadfoot.com/</link><image><url>https://www.davidbroadfoot.com/favicon.png</url><title>David Broadfoot</title><link>https://www.davidbroadfoot.com/</link></image><generator>Ghost 2.1</generator><lastBuildDate>Sat, 18 Apr 2026 22:16:17 GMT</lastBuildDate><atom:link href="https://www.davidbroadfoot.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA["Deploying and Distributing Xamarin.Forms Applications" Problem Solver]]></title><description><![CDATA[This blog post supports the sample code for the "Deploying and Distributing Xamarin.Forms Applications" course on Pluralsight. ]]></description><link>https://www.davidbroadfoot.com/deploying-distributing-xamarin-forms-applications-problem-solver/</link><guid isPermaLink="false">5ea810c99117cd16c040fa2e</guid><category><![CDATA[Xamarin]]></category><category><![CDATA[Pluralsight]]></category><category><![CDATA[Xamarin.Forms]]></category><dc:creator><![CDATA[David Broadfoot]]></dc:creator><pubDate>Mon, 27 Jul 2020 21:11:09 GMT</pubDate><media:content url="https://www.davidbroadfoot.com/content/images/2020/07/deploying-distributing-xamarin-forms-applications-v1.png" medium="image"/><content:encoded><![CDATA[<img src="https://www.davidbroadfoot.com/content/images/2020/07/deploying-distributing-xamarin-forms-applications-v1.png" alt=""Deploying and Distributing Xamarin.Forms Applications" Problem Solver"><p>This blog post supports the sample code for th<a href="https://www.pluralsight.com/courses/deploying-distributing-xamarin-forms-applications">e</a> "<a href="https://pluralsight.pxf.io/10549">Deploying and Distributing Xamarin.Forms Applications</a>" course on Pluralsight. </p><p>I'll update this post if any common issues are identified, along with their solutions.</p><p>Currently there are no common issues with the course. </p><p>You can check it out here: <a href="https://pluralsight.pxf.io/10549">Deploying and Distributing Xamarin.Forms Applications</a></p>]]></content:encoded></item><item><title><![CDATA["Getting Started with Xamarin.Essentials in Xamarin.Forms" Problem Solver]]></title><description><![CDATA[This blog post supports the sample code for the "Getting Started with Xamarin.Essentials in Xamarin.Forms" course on Pluralsight.]]></description><link>https://www.davidbroadfoot.com/getting-started-with-xamarin-essentials-in-xamarin-forms-problem-solver/</link><guid isPermaLink="false">5ed77915f6402b04e0c65140</guid><category><![CDATA[Xamarin]]></category><category><![CDATA[Pluralsight]]></category><category><![CDATA[Xamarin.Forms]]></category><dc:creator><![CDATA[David Broadfoot]]></dc:creator><pubDate>Mon, 30 Sep 2019 21:26:00 GMT</pubDate><media:content url="https://www.davidbroadfoot.com/content/images/2020/07/xamarin-essentials-forms-getting-started-v1.png" medium="image"/><content:encoded><![CDATA[<img src="https://www.davidbroadfoot.com/content/images/2020/07/xamarin-essentials-forms-getting-started-v1.png" alt=""Getting Started with Xamarin.Essentials in Xamarin.Forms" Problem Solver"><p>This blog post supports the sample code for the "<a href="https://pluralsight.pxf.io/X3OY5">Getting Started with Xamarin.Essentials in Xamarin.Forms</a>" course on Pluralsight.</p><p>I'll update this post if any common issues are identified, along with their solutions.</p><p>Currently there are no common issues with the course.</p><p>You can check it out here: <a href="https://pluralsight.pxf.io/X3OY5">Getting Started with Xamarin.Essentials in Xamarin.Forms</a></p>]]></content:encoded></item><item><title><![CDATA[Creating a Visual Studio solution item template]]></title><description><![CDATA[<p>Recently I've been using the excellent <a href="https://marketplace.visualstudio.com/items?itemName=vs-publisher-1392591.CakeforVisualStudio">Cake for Visual Studio</a> extension. It makes working with Cake build scripts inside Visual Studio that much easier with task runner integration, item templates and (some) syntax highlighting.</p><p>While the item template for adding a basic Cake build script is great, it only works</p>]]></description><link>https://www.davidbroadfoot.com/creating-a-visual-studio-solution-item-template/</link><guid isPermaLink="false">5c45a21e8d79db1b04ec07ea</guid><category><![CDATA[Visual Studio]]></category><category><![CDATA[.NET]]></category><dc:creator><![CDATA[David Broadfoot]]></dc:creator><pubDate>Mon, 21 Jan 2019 09:00:00 GMT</pubDate><media:content url="https://www.davidbroadfoot.com/content/images/2019/01/solution-item-template-2.png" medium="image"/><content:encoded><![CDATA[<img src="https://www.davidbroadfoot.com/content/images/2019/01/solution-item-template-2.png" alt="Creating a Visual Studio solution item template"><p>Recently I've been using the excellent <a href="https://marketplace.visualstudio.com/items?itemName=vs-publisher-1392591.CakeforVisualStudio">Cake for Visual Studio</a> extension. It makes working with Cake build scripts inside Visual Studio that much easier with task runner integration, item templates and (some) syntax highlighting.</p><p>While the item template for adding a basic Cake build script is great, it only works when you use the <code>Add New Item</code> functionality on a C# project. However, the majority of our build scripts sit at the solution level (inside the <code>Solution Items</code> folder) so we couldn't take advantage of this template when adding a new item to the solution itself.</p><p>Luckily the extension is open source so we can see how the <a href="https://github.com/cake-build/cake-vs/blob/develop/template/ItemTemplate/ItemTemplate.vstemplate">current item template</a> works:</p><pre><code>&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;VSTemplate Version="3.0.0" Type="Item" xmlns="http://schemas.microsoft.com/developer/vstemplate/2005" xmlns:sdk="http://schemas.microsoft.com/developer/vstemplate-sdkextension/2010"&gt;
  &lt;TemplateData&gt;
    &lt;Name&gt;Cake Build Script&lt;/Name&gt;
    &lt;Description&gt;Basic Cake build script with a sample task&lt;/Description&gt;
    &lt;Icon&gt;ItemTemplate.ico&lt;/Icon&gt;
    &lt;TemplateID&gt;7d181506-47e9-4f9d-8ac3-5ac65f6b8354&lt;/TemplateID&gt;
    &lt;ProjectType&gt;CSharp&lt;/ProjectType&gt;
    &lt;NumberOfParentCategoriesToRollUp&gt;1&lt;/NumberOfParentCategoriesToRollUp&gt;
    &lt;DefaultName&gt;build.cake&lt;/DefaultName&gt;
  &lt;/TemplateData&gt;
  &lt;TemplateContent&gt;
    &lt;ProjectItem ReplaceParameters="false"&gt;build.cake&lt;/ProjectItem&gt;
  &lt;/TemplateContent&gt;
&lt;/VSTemplate&gt;</code></pre><p>The <code>&lt;ProjectType&gt;</code> element is set to <code>CSharp</code> which explains why it appears for new items in C# projects but not for solution items.</p><p>According to the <a href="https://docs.microsoft.com/en-us/visualstudio/extensibility/projecttype-element-visual-studio-templates?view=vs-2017">Visual Studio template schema</a> the <code>ProjectType</code> element must contain one of the following values:</p><ul><li><code>CSharp</code>: Specifies that the template creates a Visual C# project or item.</li><li><code>VisualBasic</code>: Specifies that the template creates a Visual Basic project or item.</li><li><code>Web</code>: Specifies that the template creates a Web project or item.</li></ul><p>None of which sound like they will work for a Solution item.</p><p>It turns out this mustn't be a common use case, as checking out the Online Solution Item templates revealed only one other template (although it does have over 8,000 downloads).</p><figure class="kg-card kg-image-card"><img src="https://www.davidbroadfoot.com/content/images/2019/01/image-5.png" class="kg-image" alt="Creating a Visual Studio solution item template"></figure><p>Having a look at Runsettings' <a href="https://github.com/OsirisTerje/RunSettings/blob/master/AllTemplate/MyTemplate.vstemplate"><code>.vstemplate</code> file</a> revealed an undocumented <code>ProjectType</code> of <code>General</code> to get an Item Template to appear in the <code>Add New Item - Solution Items</code> dialog - exactly what we needed!</p><p>So the last step was to create a new item template for Cake, with <code>&lt;ProjectType&gt;</code> of <code>General</code> and submit a <a href="https://github.com/cake-build/cake-vs/pull/96">pull request</a> to have it included in the addin. Now we can add a new Cake build script at the solution level with ease!</p>]]></content:encoded></item><item><title><![CDATA[How to bind all interfaces of a service using Microsoft's DependencyInjection framework]]></title><description><![CDATA[<p>While working on our new Xamarin mobile app we migrated parts of our code base from .NET Framework to .NET Standard. This meant we needed a new dependency injection container for .NET Standard and Microsoft's <a href="https://www.nuget.org/packages/Microsoft.Extensions.DependencyInjection/">DependencyInjection</a> framework (as used in ASP.NET Core) ticked all the boxes... except for one.</p>]]></description><link>https://www.davidbroadfoot.com/how-to-bind-all-interfaces-with-microsoft-dependencyinjection-framework/</link><guid isPermaLink="false">5c31d32247d6df0f0c439624</guid><category><![CDATA[.NET-Standard]]></category><category><![CDATA[Dependency Injection]]></category><dc:creator><![CDATA[David Broadfoot]]></dc:creator><pubDate>Sun, 06 Jan 2019 09:00:00 GMT</pubDate><media:content url="https://www.davidbroadfoot.com/content/images/2019/01/hand-523231_1280.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://www.davidbroadfoot.com/content/images/2019/01/hand-523231_1280.jpg" alt="How to bind all interfaces of a service using Microsoft's DependencyInjection framework"><p>While working on our new Xamarin mobile app we migrated parts of our code base from .NET Framework to .NET Standard. This meant we needed a new dependency injection container for .NET Standard and Microsoft's <a href="https://www.nuget.org/packages/Microsoft.Extensions.DependencyInjection/">DependencyInjection</a> framework (as used in ASP.NET Core) ticked all the boxes... except for one. </p><p>Our requirements were straightforward:</p><p>☑ Must run on all platforms including web, desktop and mobile.</p><p>☑ Must support constructor injection.</p><p>☑ Modules that register services with the container should depend on a stable abstraction.</p><p>☒ It should be simple to register services that implement multiple interfaces.</p><p>Unfortunately, Microsoft's framework required us to manually bind all interfaces for a particular service. An unnecessary burden and one feature we took for granted with our previous abstraction (<a href="https://particular.net/nservicebus">NServiceBus' </a>Configurer).</p><p>The NuGet package <code><a href="https://www.nuget.org/packages/Microsoft.Extensions.DependencyInjection.Abstractions/">Microsoft.Extensions.DependencyInjection.Abstractions</a></code> provides two main interfaces</p><ul><li><code>IServiceCollection</code> - used to register interfaces to implementations for a specific lifetime with the container</li></ul><pre><code>void RegisterServices(IServiceCollection services)
{
  services.AddScoped&lt;IMyDependency, MyDependency&gt;();
  services.AddTransient&lt;IOperationTransient, Operation&gt;();
  services.AddScoped&lt;IOperationScoped, Operation&gt;();
  services.AddSingleton&lt;IOperationSingleton, Operation&gt;();
  services.AddSingleton&lt;IOperationSingletonInstance&gt;(new Operation());
}
</code></pre><ul><li><code>IServiceProvider</code> - used to build instances of interfaces/services</li></ul><pre><code>void BuildServices(IServiceProvider provider)
{
  var dependency1 = provider.GetRequiredService&lt;IMyDependency&gt;();
  var operation1 = provider.GetService&lt;IOperationTransient&gt;();
}
</code></pre><p>In order to meet our last requirement and simplify registering types, we created extension methods on <code>IServiceCollection</code> based off <a href="https://github.com/Particular/NServiceBus.Ninject/blob/develop/src/NServiceBus.Ninject/NinjectObjectBuilder.cs">the work done by Particular/NServiceBus on their own DI adapters</a>.</p><pre><code>/// &lt;summary&gt;
/// Registers the type &lt;see paramref="TType"/&gt; and all its alias (interfaces + base type) with the container with the specified &lt;see paramref="lifetime"/&gt;
/// &lt;/summary&gt;
/// &lt;typeparam name="TType"&gt;&lt;/typeparam&gt;
/// &lt;param name="services"&gt;&lt;/param&gt;
/// &lt;param name="lifetime"&gt;&lt;/param&gt;
/// &lt;returns&gt;&lt;/returns&gt;
public static IServiceCollection RegisterComponent&lt;TType&gt;(this IServiceCollection services, ServiceLifetime lifetime)
{
  var type = typeof(TType);
  
  services.Add(new ServiceDescriptor(type, type, lifetime));
  
  BindAliasesOfComponentToComponent(services, type, lifetime);
  
  return services;
}</code></pre><p>In the above code we first add a service descriptor that maps the type to itself, then we bind all of its aliases (interfaces) to itself which looks like:</p><pre><code>private static void BindAliasesOfComponentToComponent(IServiceCollection serviceCollection, Type component, ServiceLifetime lifetime)
{
  var services = GetAllServices(component).Where(t=&gt; t != component);

  foreach (var service in services)
  {
      // Bind all interfaces to a factory method which builds the implementation type
      serviceCollection.Add(new ServiceDescriptor(service, ctx =&gt; ctx.GetService(component), lifetime));
  }

  var baseType = component.BaseType;

  if (baseType == null || !baseType.IsAbstract)
  {
      return;
  }
  
  // Don't forget to bind an abstract base type to the implementation
  serviceCollection.Add(new ServiceDescriptor(baseType, ctx =&gt; ctx.GetService(component), lifetime));
}</code></pre><p>We use reflection to recursively find all of a type's interfaces:</p><pre><code>static IEnumerable&lt;Type&gt; GetAllServices(Type type)
{
  if (type == null)
  {
      return new List&lt;Type&gt;();
  }

  var result = new List&lt;Type&gt;(type.GetInterfaces())
  {
      type
  };

  foreach (var interfaceType in type.GetInterfaces())
  {
      result.AddRange(GetAllServices(interfaceType));
  }

  return result.Distinct();
}</code></pre><p>Finally in our module we can use this new extension method to automatically bind a type to all of its interfaces:</p><pre><code>using App.Extensions;
using Microsoft.Extensions.DependencyInjection;

public class ServiceAgent : IServiceAgent, IWantNotifications
{

}

public class Module
{
  public void Initialize(IServiceCollection services)
  {    
    services.RegisterComponent&lt;ServiceAgent&gt;(ServiceLifetime.Singleton);
  }
}
</code></pre><p>In this example the interfaces <code>IServiceAgent</code> and <code>IWantNotifications</code> are bound to the same singleton class <code>ServiceAgent</code>.  They can now be built using <code>provider.GetService&lt;IServiceAgent&gt;()</code> or used in constructor injection for other services.</p>]]></content:encoded></item><item><title><![CDATA[How to debug internal NuGet packages in Xamarin]]></title><description><![CDATA[Until Xamarin supports SourceLink here is an alternative method to make debugging into internal NuGet packages much easier.]]></description><link>https://www.davidbroadfoot.com/how-to-debug-internal-nuget-packages-in-xamarin/</link><guid isPermaLink="false">5c30606f4c710f35acdd282f</guid><category><![CDATA[Xamarin]]></category><category><![CDATA[NuGet]]></category><category><![CDATA[.NET]]></category><category><![CDATA[Debugging]]></category><category><![CDATA[.NET-Standard]]></category><dc:creator><![CDATA[David Broadfoot]]></dc:creator><pubDate>Sat, 05 Jan 2019 03:00:00 GMT</pubDate><media:content url="https://www.davidbroadfoot.com/content/images/2019/01/cover-1.png" medium="image"/><content:encoded><![CDATA[<h3 id="at-smokeball-we-design-our-software-using-a-service-oriented-architecture-which-means-our-application-projects-tend-to-be-no-more-than-a-shell-that-reference-a-bunch-of-internal-nuget-packages-">At Smokeball we design our software using a service-oriented architecture which means our application projects tend to be no more than a shell that reference a bunch of internal NuGet packages.</h3><img src="https://www.davidbroadfoot.com/content/images/2019/01/cover-1.png" alt="How to debug internal NuGet packages in Xamarin"><p></p><p>Different teams are responsible for each of these NuGet packages (and there are a lot of them!) so including the projects in the main Xamarin application solution isn't an option. Unfortunately, this can make debugging and stepping through these internal components much harder when they're added via NuGet packages.</p><p>While <a href="https://github.com/dotnet/sourcelink">SourceLink</a> can help us debug and step in to these components in our desktop applications, it <a href="https://github.com/xamarin/Xamarin.Forms/issues/2165" rel="noopener">isn’t currently supported in Xamarin</a>.</p><p>But there is another way! Here is how we build our NuGet packages so that developers can easily debug them if needed from the main application. This method will work for internal NuGet packages within an organisation - it won't work for third party NuGet packages (unless they follow this method too!)</p><p>Ultimately this method boils down to 2 basic concepts</p><ul><li>Include the .pdb file in the NuGet package</li><li>Ensure the source file locations baked in to the .pdb are mapped to a well-known location</li></ul><p>Sounds simple right? However, there are a few gotchas to keep in mind.</p><p>Let's start with a .NET Standard 2.0 class library for our Reminders component that we'll want to include in our Xamarin app.</p><p>The new SDK-style projects have made it trivial to create a NuGet package from a project using either Visual Studio or the donet cli.</p><p><code><a href="https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-pack?tabs=netcore2x">dotnet pack</a> ItOps.Reminders.Xamarin.csproj</code> </p><p>But the resulting NuGet package (.nupkg) will only contain the ItOps.Reminders.Xamarin.dll, not the .pdb. </p><p>If we were to pass in the <code>--include-symbols</code> to the pack command above, it would generate a separate *.symbols.nupkg that contains the .pdb file we need for debugging.</p><p>However, we can get a better debugging experience by including it in the main package. <a href="https://docs.microsoft.com/en-us/dotnet/standard/library-guidance/nuget">According to Microsoft</a>:</p><blockquote>Embedding symbol files in the main NuGet package gives developers a better debugging experience by default. They don't need to find and configure the NuGet symbol server in their IDE to get symbol files.</blockquote><blockquote>The downside to embedded symbol files is they increase the package size by about 30% for .NET libraries compiled using SDK-style projects. If package size is a concern, you should publish symbols in a symbol package instead.</blockquote><p>In order to get all the files we need in the main NuGet package, we can add this property to our .csproj file.  </p><pre><code>AllowedOutputExtensionsInPackageBuildOutputFolder</code></pre><pre><code>&lt;Project Sdk="Microsoft.NET.Sdk"&gt;
  &lt;PropertyGroup&gt; 
      &lt;AllowedOutputExtensionsInPackageBuildOutputFolder&gt;$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb;.xml;&lt;/AllowedOutputExtensionsInPackageBuildOutputFolder&gt;
  &lt;/PropertyGroup&gt;
    &lt;!-- Other properties ommitted --&gt;
&lt;/Project&gt;
</code></pre><p>Now when we run <code>dotnet pack</code> the resulting NuGet package will contain our assembly and the .pdb file. Success!</p><p>This NuGet package can be referenced in our main Xamarin application and we can now step in to the Reminders code. (Make sure the <a href="https://docs.microsoft.com/en-us/visualstudio/debugger/just-my-code?view=vs-2017">Just My Code setting is disabled in Visual Studio</a>)</p><p>While this works for a NuGet package built and debugged locally on the same machine, chances are that we won't be able to debug a NuGet package built on our Continuous Integration build server.</p><p>The reason for this is that when a .pdb file is generated, it embeds the location of the source code.  Because each developer (and build agent) checks out the source code to a different location, unless our code is also in the same location Visual Studio won't be able to locate the source when debugging.</p><p>We can rewrite the source code location inside the pdb while it is being generated by making use of the <code>PathMap</code> property in our .csproj file.</p><pre><code>&lt;PathMap&gt;$(MSBuildProjectDirectory)=C:\repos\itops\reminders\xamarin&lt;/PathMap</code></pre><p>In this case we are mapping the current project build directory (which could be a random folder on the build agent) to a well-known location.</p><p>Developers can then either move their local copy of the source code to C:\repos OR create a <a href="https://www.howtogeek.com/howto/16226/complete-guide-to-symbolic-links-symlinks-on-windows-or-linux/">directory junction</a> to map this path to the actual location of their repository (e.g. D:\code).</p><p><code>mklink /J D:\code C:\repos</code></p><p>With all this in place, we can now debug in to NuGet packages built locally and on the build server.</p><p>One last bit to tidy up. Rather than having to modify all our .csproj files individually to set these properties, we can take advantage of a single <a href="https://docs.microsoft.com/en-us/visualstudio/msbuild/customize-your-build?view=vs-2017">Directory.Build.props</a> file.</p><p>By checking in this file to the root of our git repository, it will automatically apply these settings to <strong>every </strong>project in the repository.</p><pre><code>&lt;Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"&gt;
  &lt;PropertyGroup&gt;
    &lt;AllowedOutputExtensionsInPackageBuildOutputFolder&gt;$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb;.xml&lt;/AllowedOutputExtensionsInPackageBuildOutputFolder&gt;
    &lt;PathMap&gt;$(MSBuildThisFileDirectory)=C:\repos\itops&lt;/PathMap&gt;
      
    &lt;!-- Additional properties that we'd like to apply repository wide --&gt;
    &lt;Company&gt;Smokeball&lt;/Company&gt;
    &lt;Authors&gt;Smokeball&lt;/Authors&gt;
    &lt;DebugSymbols&gt;true&lt;/DebugSymbols&gt;
    &lt;GenerateDocumentationFile&gt;true&lt;/GenerateDocumentationFile&gt;
  &lt;/PropertyGroup&gt;
&lt;/Project&gt;
</code></pre><p>Once Xamarin finally supports SourceLink we will be able to do away with this method and Visual Studio will be able to pull the source code directly from our remote git repository.</p><h3 id="additional-notes">Additional notes</h3><p>To inspect the file paths embedded in the pdb you can use the <a href="https://github.com/KirillOsenkov/Dia2Dump/releases">Dia2Dump </a>tool for Windows pdb files (DebugType = Full)</p><p><code>Dia2Dump.exe ItOps.Reminders.Xamarin.pdb</code></p><p>or for a portable .pdb (DebugType = Portable) you can view the file paths by opening it in Notepad++.</p><figure class="kg-card kg-image-card"><img src="https://www.davidbroadfoot.com/content/images/2019/01/image-2.png" class="kg-image" alt="How to debug internal NuGet packages in Xamarin"></figure><p>One last thing - if you use <a href="https://inedo.com/proget">ProGet</a> to host your NuGet feeds, then ensure the option to strip symbol files from packages is NOT selected.</p><figure class="kg-card kg-image-card"><img src="https://www.davidbroadfoot.com/content/images/2019/01/image-4.png" class="kg-image" alt="How to debug internal NuGet packages in Xamarin"></figure>]]></content:encoded></item></channel></rss>