<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Benny Michielsen</title>
	<atom:link href="http://blog.bennymichielsen.be/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.bennymichielsen.be</link>
	<description>.net developer with a touch of Cocoa</description>
	<lastBuildDate>Thu, 12 Mar 2020 13:47:10 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=5.3.21</generator>
	<item>
		<title>Azure Day Poland – Multi tenant apps with Azure and Azure DevOps</title>
		<link>http://blog.bennymichielsen.be/2019/05/01/azure-day-poland-multi-tenant-apps-with-azure-and-azure-devops/</link>
				<comments>http://blog.bennymichielsen.be/2019/05/01/azure-day-poland-multi-tenant-apps-with-azure-and-azure-devops/#respond</comments>
				<pubDate>Wed, 01 May 2019 19:31:00 +0000</pubDate>
		<dc:creator><![CDATA[BennyM]]></dc:creator>
				<category><![CDATA[Software Development]]></category>
		<category><![CDATA[azure]]></category>
		<category><![CDATA[DevOps]]></category>

		<guid isPermaLink="false">http://blog.bennymichielsen.be/?p=1504</guid>
				<description><![CDATA[I was honoured to speak at Azure Day in Poland on 29th March 2019. It was the perfect spot for my talk featuring football tenants. There was quite a crowd for the talk and some people approached me after the talk for some more info. It was also fun to explore the city. Recordings of &#8230; <p class="link-more"><a href="http://blog.bennymichielsen.be/2019/05/01/azure-day-poland-multi-tenant-apps-with-azure-and-azure-devops/" class="more-link">Continue reading<span class="screen-reader-text"> "Azure Day Poland – Multi tenant apps with Azure and Azure DevOps"</span></a></p>]]></description>
								<content:encoded><![CDATA[
<p>I was honoured to speak at Azure Day in Poland on 29th March 2019. It was the perfect spot for my talk featuring football tenants.</p>



<figure class="wp-block-embed-twitter aligncenter wp-block-embed is-type-rich is-provider-twitter"><div class="wp-block-embed__wrapper">
<div class="twitter-tweet"><blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">I can not be at a better place for my talk. Want to know why? Come to my talk this afternoon. <a href="https://twitter.com/hashtag/Azure?src=hash&amp;ref_src=twsrc%5Etfw">#Azure</a> <a href="https://twitter.com/hashtag/azuredaypl?src=hash&amp;ref_src=twsrc%5Etfw">#azuredaypl</a>  <a href="https://twitter.com/AzureDayPL?ref_src=twsrc%5Etfw">@AzureDayPL</a> <a href="https://t.co/zkfgGUb6HI">pic.twitter.com/zkfgGUb6HI</a></p>&mdash; Benny Michielsen (@bennymichielsen) <a href="https://twitter.com/bennymichielsen/status/1111553694456299521?ref_src=twsrc%5Etfw">March 29, 2019</a></blockquote></div>
</div></figure>



<p>There was quite a crowd for the talk and some people approached me after the talk for some more info.  It was also fun to explore the city.</p>



<figure class="wp-block-embed-twitter wp-block-embed is-type-rich is-provider-twitter"><div class="wp-block-embed__wrapper">
<div class="twitter-tweet"><blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr"><a href="https://twitter.com/bennymichielsen?ref_src=twsrc%5Etfw">@bennymichielsen</a> during <a href="https://twitter.com/AzureDayPL?ref_src=twsrc%5Etfw">@AzureDayPL</a> <a href="https://t.co/esVRr2M0tg">pic.twitter.com/esVRr2M0tg</a></p>&mdash; Przemysław Pogorzelec (@ppogorzelec) <a href="https://twitter.com/ppogorzelec/status/1111611320070299655?ref_src=twsrc%5Etfw">March 29, 2019</a></blockquote></div>
</div></figure>



<div class="wp-block-image"><figure class="aligncenter size-large"><img src="https://blog.bennymichielsen.be/wp-content/uploads/2020/03/thumbnail-1-1024x682.jpeg" alt="" class="wp-image-1505" srcset="http://blog.bennymichielsen.be/wp-content/uploads/2020/03/thumbnail-1-1024x682.jpeg 1024w, http://blog.bennymichielsen.be/wp-content/uploads/2020/03/thumbnail-1-300x200.jpeg 300w, http://blog.bennymichielsen.be/wp-content/uploads/2020/03/thumbnail-1-768x512.jpeg 768w, http://blog.bennymichielsen.be/wp-content/uploads/2020/03/thumbnail-1-1536x1024.jpeg 1536w, http://blog.bennymichielsen.be/wp-content/uploads/2020/03/thumbnail-1.jpeg 2000w" sizes="(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px" /></figure></div>



<figure class="wp-block-image size-large"><img src="https://blog.bennymichielsen.be/wp-content/uploads/2020/03/thumbnail-1024x682.jpeg" alt="" class="wp-image-1506" srcset="http://blog.bennymichielsen.be/wp-content/uploads/2020/03/thumbnail-1024x682.jpeg 1024w, http://blog.bennymichielsen.be/wp-content/uploads/2020/03/thumbnail-300x200.jpeg 300w, http://blog.bennymichielsen.be/wp-content/uploads/2020/03/thumbnail-768x512.jpeg 768w, http://blog.bennymichielsen.be/wp-content/uploads/2020/03/thumbnail-1536x1024.jpeg 1536w, http://blog.bennymichielsen.be/wp-content/uploads/2020/03/thumbnail.jpeg 2000w" sizes="(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px" /></figure>



<p>Recordings of the talk are available from Moscow and Vilnius.</p>



<figure class="wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe title="Create and Deploy Multi Tenant Applications on Azure with Azure DevOps by Benny Michielsen" width="525" height="295" src="https://www.youtube.com/embed/A9t4_OHXprA?feature=oembed" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
</div></figure>



<figure class="wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe title="Benny Michielsen - Secure Multi tenant Apps with Azure and VSTS" width="525" height="295" src="https://www.youtube.com/embed/wUp3_n6M2RU?feature=oembed" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
</div></figure>
]]></content:encoded>
							<wfw:commentRss>http://blog.bennymichielsen.be/2019/05/01/azure-day-poland-multi-tenant-apps-with-azure-and-azure-devops/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
							</item>
		<item>
		<title>DevOps Pro &#8211; Multi tenant apps with Azure and Azure DevOps</title>
		<link>http://blog.bennymichielsen.be/2019/03/21/devops-pro-multi-tenant-apps-with-azure-and-azure-devops/</link>
				<comments>http://blog.bennymichielsen.be/2019/03/21/devops-pro-multi-tenant-apps-with-azure-and-azure-devops/#comments</comments>
				<pubDate>Thu, 21 Mar 2019 14:35:01 +0000</pubDate>
		<dc:creator><![CDATA[BennyM]]></dc:creator>
				<category><![CDATA[Software Development]]></category>
		<category><![CDATA[ARM]]></category>
		<category><![CDATA[azure]]></category>
		<category><![CDATA[DevOps]]></category>

		<guid isPermaLink="false">http://blog.bennymichielsen.be/?p=1488</guid>
				<description><![CDATA[The latest two talks I gave were at the DevOps Pro conferences in Moscow and Vilnius. Unlike most of my talks, shocking, this one was based on stuff that&#8217;s actually running in production and not just me trying out something new and sharing my experiences. I&#8217;m never happy with how it went but perhaps that&#8217;s &#8230; <p class="link-more"><a href="http://blog.bennymichielsen.be/2019/03/21/devops-pro-multi-tenant-apps-with-azure-and-azure-devops/" class="more-link">Continue reading<span class="screen-reader-text"> "DevOps Pro &#8211; Multi tenant apps with Azure and Azure DevOps"</span></a></p>]]></description>
								<content:encoded><![CDATA[
<p>The latest two talks I gave were at the DevOps Pro conferences in <a href="https://www.devopspro.ru/2018/">Moscow</a> and <a href="https://devopspro.lt/">Vilnius</a>. Unlike most of my talks, shocking, this one was based on stuff that&#8217;s actually running in production and not just me trying out something new and sharing my experiences.  </p>



<figure class="wp-block-embed-twitter aligncenter wp-block-embed is-type-rich is-provider-twitter"><div class="wp-block-embed__wrapper">
<div class="twitter-tweet"><blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">Next up: <a href="https://twitter.com/bennymichielsen?ref_src=twsrc%5Etfw">@bennymichielsen</a> on multi tenancy with <a href="https://twitter.com/hashtag/AzureDevOps?src=hash&amp;ref_src=twsrc%5Etfw">#AzureDevOps</a> and <a href="https://twitter.com/hashtag/Azure?src=hash&amp;ref_src=twsrc%5Etfw">#Azure</a>. This is one of the areas <a href="https://twitter.com/OctopusDeploy?ref_src=twsrc%5Etfw">@OctopusDeploy</a> does an awesome job. Let’s see how this can be done with <a href="https://twitter.com/hashtag/AzureDevOps?src=hash&amp;ref_src=twsrc%5Etfw">#AzureDevOps</a> <a href="https://t.co/qLQWKkEGhT">pic.twitter.com/qLQWKkEGhT</a></p>&mdash; Erwin Staal (@erwin_staal) <a href="https://twitter.com/erwin_staal/status/1108673826827788290?ref_src=twsrc%5Etfw">March 21, 2019</a></blockquote></div>
</div></figure>



<p>I&#8217;m never happy with how it went but perhaps that&#8217;s just me. The questions and feedback I get is almost always positive but I&#8217;m not sure if that&#8217;s just people being friendly or real feedback. <a rel="noreferrer noopener" aria-label="Imposter syndrome (opens in a new tab)" href="https://en.wikipedia.org/wiki/Impostor_syndrome" target="_blank">Imposter syndrome</a> anyone?  Anyway, enough about the talks. Show me some content! The slides can be found <a href="http://blog.bennymichielsen.be/wp-content/uploads/2019/03/TacklingMultiTenantApps.pdf" target="_blank" rel="noreferrer noopener" aria-label="here (opens in a new tab)">here</a>, although I don&#8217;t think they will help you much, most content is in the code and it turns out I can hardly show anything of it during a 45 minute talk.</p>



<p>The talk is divided in three parts:<br></p>



<ul><li>Secure<ul><li>Azure AD with Users, App Registrations, Application Roles etc.</li><li>KeyVault</li><li>Managed Identity</li></ul></li><li>Isolation<ul><li>Showing some approaches on how to architect solutions</li></ul></li><li>Automation<ul><li>Demo 1 is focused on a single app where tenants have their own data store but share the app service. I use Azure automation to update the application manifest in AD and deploy ARM templates</li><li>Demo 2 is the cool guy in town but never receives enough attention. I use the REST api of Azure DevOps to update a release definition, add a stage, configure some variables and deploy an entire new resource group.</li></ul></li></ul>



<p>I will create a few additional blogposts to illustrate how it works. Next week I&#8217;ll be at <a href="https://azureday.pro/" target="_blank" rel="noreferrer noopener" aria-label="AzureDay (opens in a new tab)">AzureDay</a> so I can try it again.</p>



<figure class="wp-block-embed-twitter aligncenter wp-block-embed is-type-rich is-provider-twitter"><div class="wp-block-embed__wrapper">
<div class="twitter-tweet"><blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">&quot;You don&#39;t want sensitive information in your configuration files&quot; <a href="https://twitter.com/bennymichielsen?ref_src=twsrc%5Etfw">@bennymichielsen</a>, &quot;Secure Multi-tenant Apps with Azure and VSTS&quot;, <a href="https://twitter.com/hashtag/DevOpsProMoscow?src=hash&amp;ref_src=twsrc%5Etfw">#DevOpsProMoscow</a> <a href="https://twitter.com/hashtag/Azure?src=hash&amp;ref_src=twsrc%5Etfw">#Azure</a> <a href="https://twitter.com/platformsh?ref_src=twsrc%5Etfw">@platformsh</a> <a href="https://t.co/o8W2z12Ui2">pic.twitter.com/o8W2z12Ui2</a></p>&mdash; robertDouglass (@robertDouglass) <a href="https://twitter.com/robertDouglass/status/1062679014664474624?ref_src=twsrc%5Etfw">November 14, 2018</a></blockquote></div>
</div></figure>



<p></p>
]]></content:encoded>
							<wfw:commentRss>http://blog.bennymichielsen.be/2019/03/21/devops-pro-multi-tenant-apps-with-azure-and-azure-devops/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
							</item>
		<item>
		<title>Auditing with EF Core and Sql Server – Part 2: Triggers, Session context and dependency injection</title>
		<link>http://blog.bennymichielsen.be/2017/11/21/auditing-with-ef-core-and-sql-server-part-2-triggers-and-sp_set_session_context/</link>
				<comments>http://blog.bennymichielsen.be/2017/11/21/auditing-with-ef-core-and-sql-server-part-2-triggers-and-sp_set_session_context/#comments</comments>
				<pubDate>Tue, 21 Nov 2017 05:00:15 +0000</pubDate>
		<dc:creator><![CDATA[BennyM]]></dc:creator>
				<category><![CDATA[Software Development]]></category>
		<category><![CDATA[efcore]]></category>
		<category><![CDATA[sql]]></category>

		<guid isPermaLink="false">http://blog.bennymichielsen.be/?p=1432</guid>
				<description><![CDATA[In part 1 I looked at using temporal tables to cover auditing requirements. Although a great feature, it did not quite cover the scenario I was after. I wanted a solution that did not impact my .NET code or at least keep the necessary change as small as possible. So I decided to use a &#8230; <p class="link-more"><a href="http://blog.bennymichielsen.be/2017/11/21/auditing-with-ef-core-and-sql-server-part-2-triggers-and-sp_set_session_context/" class="more-link">Continue reading<span class="screen-reader-text"> "Auditing with EF Core and Sql Server – Part 2: Triggers, Session context and dependency injection"</span></a></p>]]></description>
								<content:encoded><![CDATA[<p>In <a href="http://blog.bennymichielsen.be/2017/11/07/auditing-with-ef-core-and-sql-server-part-1/">part 1</a> I looked at using temporal tables to cover auditing requirements. Although a great feature, it did not quite cover the scenario I was after. I wanted a solution that did not impact my .NET code or at least keep the necessary change as small as possible.</p>
<p>So I decided to use a SQL feature I tend to avoid. Triggers. There I&#8217;ll say it again: triggers.</p>
<p>They are very powerful, but can be misused. Certainly in legacy systems where people went all out with them, you can be spending quite some time looking into where your SQL statements are actually processed or why your delete is doing an update. But for my current use case they seemed to be the right fit. It&#8217;s a feature of the datastore and it would keep all logic out of my code.</p>
<p>So first I created an AuditInfo class in my codebase so I could generate a migration with the create table statement and, should I need it, be able to query it in code.</p>
<pre lang="csharp">
public class AuditInfo
{
    public long Id { get; set; }
    public string SchemaName { get; set; }
    public string TableName { get; set; }
    public long RowId { get; set; }
    public DateTime ActionDate { get; set; }
    public string Action { get; set; }
    public string Values { get; set; }
    public string ModifiedBy { get; set; }
}
</pre>
<p>Short and simple. In my current project I gave every entity an Id, even if I could use a composite key. It just makes things a lot easier and means I can get the history of a specific row in an easy way. I also created an extension method to add an audit trigger on every entity.</p>
<pre lang="csharp">
public static class EnableAuditTriggerExtensions
{
	public static void EnableAuditTrigger(this MigrationBuilder migrationBuilder, IEntityType entityType)
	{
		var tableName = entityType.Relational().TableName;
		var schemaName = entityType.Relational().Schema ?? "dbo";
		migrationBuilder.Sql($@"
IF EXISTS (SELECT * FROM sys.triggers WHERE object_id = OBJECT_ID(N'[{schemaName}].[{tableName}_Audit]'))
DROP TRIGGER [{schemaName}].[{tableName}_Audit]");
		migrationBuilder.Sql($@"
CREATE TRIGGER [{schemaName}].[{tableName}_Audit] ON  [{schemaName}].[{tableName}]
AFTER INSERT, DELETE, UPDATE
AS 
BEGIN

SET NOCOUNT ON;
DECLARE @Action AS CHAR(1)
DECLARE @Id AS BIGINT
DECLARE @Values AS NVARCHAR(MAX)
SET @Action = NULL
SET @Id = NULL
SET @Values = NULL

IF EXISTS (SELECT * FROM inserted)
BEGIN
	IF EXISTS(SELECT * FROM deleted)
	BEGIN
		SET @Action = 'U'
	END
	ELSE
	BEGIN
		SET @Action = 'I'
	END
END
ELSE IF EXISTS(SELECT * FROM deleted)
BEGIN
	SET @Action = 'D'
END
IF @Action = 'D'
BEGIN
	INSERT INTO dbo.AuditInfo (
		SchemaName,
		TableName,
		RowId,
                ActionDate,
		ModifiedBy,
		[Action],
		[Values])
		SELECT
		'{schemaName}',
		'{tableName}',
		d.Id,
                SYSUTCDATETIME(),
		(SELECT CONVERT(nvarchar(250), SESSION_CONTEXT(N'CurrentApplicationUser'))),
		@Action,
		(SELECT * FROM deleted vals where vals.Id = d.Id FOR JSON PATH)
		FROM deleted d
END
ELSE
BEGIN
	INSERT INTO dbo.AuditInfo (
		SchemaName,
		TableName,
		RowId,
                ActionDate,
		ModifiedBy,
		[Action],
		[Values])
		SELECT
		'{schemaName}',
		'{tableName}',
		i.Id,
                SYSUTCDATETIME(),
		(SELECT CONVERT(nvarchar(250), SESSION_CONTEXT(N'CurrentApplicationUser'))),
		@Action,
		(SELECT * FROM inserted vals where vals.Id = i.Id FOR JSON PATH)
		FROM inserted i
END
END");
	}
}
</pre>
<p>Since you get access to the deleted and inserted values in a trigger I can inspect it and insert the correct values in my audit table. It&#8217;s not that complicated. </p>
<p>You can also see that I&#8217;m using &#8220;SESSION_CONTEXT&#8221;. All the users connect to the database with the same connection string, since I want to use connection pooling, but I want to log the correct application user along with the changes they made. There are several ways you can solve this but using &#8220;SESSION_CONTEXT&#8221; gives me an easy way to share information between my application and its database. It is <a href="https://docs.microsoft.com/en-us/sql/t-sql/functions/session-context-transact-sql" rel="noopener" target="_blank">a new feature</a> in SQL Server 2016 and can be used with SQL Azure. SESSION_CONTEXT allows you to associate key value pairs to your current SQLConnection. </p>
<p>Won&#8217;t this then fail because you are using the same connection for multiple users? No because if you review the log of what happens to your SQL Server you&#8217;ll notice that &#8220;sp_reset_connection&#8221; gets called. This does a couple of things, including clearing whatever is in the SESSION_CONTEXT. I tried hard to find it being explicitly mentioned on MSDN but could not find any reference. This <a href="https://blogs.msdn.microsoft.com/ialonso/2012/06/04/misconceptions-around-connection-pooling/" rel="noopener" target="_blank">article</a> proved valuable to clear up some of the underlying functionality. Since the stored procedure clears &#8220;<a href="https://docs.microsoft.com/en-us/sql/t-sql/functions/context-info-transact-sql" rel="noopener" target="_blank">CONTEXT_INFO</a>&#8221; which I could also have used but is a bit more cumbersome to work with.</p>
<p>The migration itself is then pretty straightforward. Again the same caveat as before, many to many associations need to be modelled as an entity using this approach as I iterate across all entities to add the trigger to the underlying table.</p>
<pre lang="csharp">
public partial class LogWithTrigger : Migration
{
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        foreach (var entity in TargetModel.GetEntityTypes())
        {
            if (entity.Name != typeof(AuditInfo).FullName)
            {
                migrationBuilder.EnableAuditTrigger(entity);
            }
        }
    }
}
</pre>
<p>So what remained is to actually call the stored procedure to add the current username to the key (&#8216;CurrentApplicationUser&#8217;) that&#8217;s being referenced in my trigger. I had to dig a bit into how entity framework works to get this working as I need control over the actual connection. I could just create a SqlConnection and give that to the DbContext. If you do this Entity Framework will just use the connection you supply, however I wanted to use dependency injection. I subclassed SqlServerConnection to get the additional behaviour.</p>
<p>This is the version for EFCore < 2.0:



<pre lang="csharp">
public class PrincipalAwareConnection
    : SqlServerConnection
{
    private IPrincipal principal;

    public PrincipalAwareConnection(IDbContextOptions options, ILogger<SqlServerConnection> logger, IPrincipal principal)
        : base(options, logger)
    {
        this.principal = principal;
    }

    public override async Task OpenAsync(CancellationToken cancellationToken = default(CancellationToken))
    {
        bool setSessionState = this.DbConnection.State != ConnectionState.Open;
        await base.OpenAsync();
        if (setSessionState)
        {
            SetSessionInfo();
        }
    }

    private void SetSessionInfo()
    {
        using (var cmd = base.DbConnection.CreateCommand())
        {
            cmd.Transaction = base.CurrentTransaction?.GetDbTransaction();
            cmd.CommandType = System.Data.CommandType.StoredProcedure;
            cmd.CommandText = $&#8221;sp_set_session_context&#8221;;
            var keyParameter = cmd.CreateParameter();
            cmd.Parameters.Add(keyParameter);
            keyParameter.ParameterName = &#8220;key&#8221;;
            keyParameter.Value = &#8220;CurrentApplicationUser&#8221;;
            var valueParameter = cmd.CreateParameter();
            cmd.Parameters.Add(valueParameter);
            valueParameter.ParameterName = &#8220;value&#8221;;
            valueParameter.Value = principal.Identity.Name;
            var readOnlyParameter = cmd.CreateParameter();
            cmd.Parameters.Add(readOnlyParameter);
            readOnlyParameter.ParameterName = &#8220;read_only&#8221;;
            readOnlyParameter.Value = 1;
            cmd.ExecuteNonQuery();
        }
    }

    public override void Open()
    {
        bool setSessionState = this.DbConnection.State != ConnectionState.Open;
        base.Open();
        if (setSessionState)
        {
            SetSessionInfo();
        }
    }
}
</pre>
<p>This is the version for EFCore >= 2.0:</p>
<pre lang="csharp">
public class PrincipalAwareConnection
    : SqlServerConnection
{
    private IPrincipal principal;

    public PrincipalAwareConnection(RelationalConnectionDependencies dependencies, IPrincipal principal)
        : base(dependencies)
    {
        this.principal = principal;
    }

    public override async Task<bool> OpenAsync(CancellationToken cancellationToken, bool errorsExpected = false)
    {
        bool setSessionState = this.DbConnection.State != ConnectionState.Open;
        bool opened = await base.OpenAsync(cancellationToken, errorsExpected);
        if (setSessionState)
        {
            SetSessionInfo();
        }
        return opened;
    }
    
    private void SetSessionInfo()
    {
        using (var cmd = base.DbConnection.CreateCommand())
        {
            cmd.Transaction = base.CurrentTransaction?.GetDbTransaction();
            cmd.CommandType = System.Data.CommandType.StoredProcedure;
            cmd.CommandText = $"sp_set_session_context";
            var keyParameter = cmd.CreateParameter();
            cmd.Parameters.Add(keyParameter);
            keyParameter.ParameterName = "key";
            keyParameter.Value = "CurrentApplicationUser";
            var valueParameter = cmd.CreateParameter();
            cmd.Parameters.Add(valueParameter);
            valueParameter.ParameterName = "value";
            valueParameter.Value = principal.Identity.Name;
            var readOnlyParameter = cmd.CreateParameter();
            cmd.Parameters.Add(readOnlyParameter);
            readOnlyParameter.ParameterName = "read_only";
            readOnlyParameter.Value = 1;
            cmd.ExecuteNonQuery();
        }
    }

    public override bool Open(bool errorsExpected = false)
    {
        bool setSessionState = this.DbConnection.State != ConnectionState.Open;
        var opened = base.Open(errorsExpected);
        if (setSessionState)
        {
            SetSessionInfo();
        }
        return opened;
    }
}
</pre>
<p>In order to override the default SqlServerConnection and allow for the dependency injection of &#8220;IPrincipal&#8221; I also had to modify the &#8220;ConfigureServices&#8221; method in my &#8220;Startup.cs&#8221; class.</p>
<pre lang="csharp">
services.AddEntityFrameworkSqlServer();
services.AddTransient<ISqlServerConnection, PrincipalAwareConnection>();
services.AddDbContext<MyContext>((sp, options) =>
    options.UseSqlServer(Configuration.GetConnectionString("MyConnectionString"))
           .UseInternalServiceProvider(sp));
</pre>
<p>When adding, updating or deleting rows the audit table is now populated with values.</p>
<p><a href="http://blog.bennymichielsen.be/wp-content/uploads/2017/11/Screen-Shot-2017-11-20-at-21.10.14.png"><img src="http://blog.bennymichielsen.be/wp-content/uploads/2017/11/Screen-Shot-2017-11-20-at-21.10.14-1024x85.png" alt="" width="525" height="44" class="aligncenter size-large wp-image-1454" srcset="http://blog.bennymichielsen.be/wp-content/uploads/2017/11/Screen-Shot-2017-11-20-at-21.10.14-1024x85.png 1024w, http://blog.bennymichielsen.be/wp-content/uploads/2017/11/Screen-Shot-2017-11-20-at-21.10.14-300x25.png 300w, http://blog.bennymichielsen.be/wp-content/uploads/2017/11/Screen-Shot-2017-11-20-at-21.10.14-768x63.png 768w, http://blog.bennymichielsen.be/wp-content/uploads/2017/11/Screen-Shot-2017-11-20-at-21.10.14.png 1840w" sizes="(max-width: 525px) 100vw, 525px" /></a></p>
<p>This snippet hooks up Entity Framework with the container you use in your application. So now whenever an entity is changed the audit table is filled with the correct values. Perhaps I&#8217;ll look into building a diff screen but for now I consider this the best fit for my goals. What do you think?</p>
]]></content:encoded>
							<wfw:commentRss>http://blog.bennymichielsen.be/2017/11/21/auditing-with-ef-core-and-sql-server-part-2-triggers-and-sp_set_session_context/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
							</item>
		<item>
		<title>Topconf Talinn 2017</title>
		<link>http://blog.bennymichielsen.be/2017/11/16/topconf-talinn-2017/</link>
				<comments>http://blog.bennymichielsen.be/2017/11/16/topconf-talinn-2017/#respond</comments>
				<pubDate>Thu, 16 Nov 2017 05:29:58 +0000</pubDate>
		<dc:creator><![CDATA[BennyM]]></dc:creator>
				<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[bitcoin]]></category>
		<category><![CDATA[blockchain]]></category>
		<category><![CDATA[ethereum]]></category>

		<guid isPermaLink="false">http://blog.bennymichielsen.be/?p=1437</guid>
				<description><![CDATA[I&#8217;m currently in Talinn where I&#8217;m taking part in Topconf Talinn 2017. After a day of travelling and looking around in the city my talk was scheduled in the morning of the first day. I presented my blockchain talk which I had slightly modified to fit it in the time slot of 40 minutes. This &#8230; <p class="link-more"><a href="http://blog.bennymichielsen.be/2017/11/16/topconf-talinn-2017/" class="more-link">Continue reading<span class="screen-reader-text"> "Topconf Talinn 2017"</span></a></p>]]></description>
								<content:encoded><![CDATA[<p>I&#8217;m currently in Talinn where I&#8217;m taking part in <a href="https://www.topconf.com/conference/topconf-tallinn-2017/index">Topconf Talinn 2017</a>. After a day of travelling and looking around in the city my talk was scheduled in the morning of the first day.</p>
<p><a href="http://blog.bennymichielsen.be/wp-content/uploads/2017/11/Tallinn_2017_.horizontal_preview.jpeg"><img src="http://blog.bennymichielsen.be/wp-content/uploads/2017/11/Tallinn_2017_.horizontal_preview-300x225.jpeg" alt="" width="300" height="225" class="aligncenter size-medium wp-image-1442" srcset="http://blog.bennymichielsen.be/wp-content/uploads/2017/11/Tallinn_2017_.horizontal_preview-300x225.jpeg 300w, http://blog.bennymichielsen.be/wp-content/uploads/2017/11/Tallinn_2017_.horizontal_preview-768x576.jpeg 768w, http://blog.bennymichielsen.be/wp-content/uploads/2017/11/Tallinn_2017_.horizontal_preview.jpeg 1000w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>
<p>I presented my blockchain talk which I had slightly modified to fit it in the time slot of 40 minutes. This forced me to remove some parts but still it was difficult to get it done in the allotted time. Luckily I took part in the open space lab in the afternoon where a couple of attendees approached me to learn more about the subject. My talk currently has a rating of 4.6/5.</p>
<p><a href="http://blog.bennymichielsen.be/wp-content/uploads/2017/11/26657992209_0b5a38c8d7_k.jpg"><img class="aligncenter wp-image-1438 size-large" src="http://blog.bennymichielsen.be/wp-content/uploads/2017/11/26657992209_0b5a38c8d7_k-1024x768.jpg" alt="" width="525" height="394" srcset="http://blog.bennymichielsen.be/wp-content/uploads/2017/11/26657992209_0b5a38c8d7_k-1024x768.jpg 1024w, http://blog.bennymichielsen.be/wp-content/uploads/2017/11/26657992209_0b5a38c8d7_k-300x225.jpg 300w, http://blog.bennymichielsen.be/wp-content/uploads/2017/11/26657992209_0b5a38c8d7_k-768x576.jpg 768w, http://blog.bennymichielsen.be/wp-content/uploads/2017/11/26657992209_0b5a38c8d7_k.jpg 2048w" sizes="(max-width: 525px) 100vw, 525px" /></a></p>
<p>Slides can be downloaded <a href="http://blog.bennymichielsen.be/wp-content/uploads/2017/11/Topconf_Tallinn.pdf">here</a> and the source of my Ethereum game is available on <a href="https://github.com/BennyM/bigbangblockchaingame" target="_blank" rel="noopener">GitHub</a>.</p>
<p>I haven&#8217;t applied this talk to any future conferences, so for now this is the last time I gave it. A recording of my session at NDC Oslo 2017 is also available on <a href="https://youtu.be/_dlKELBYgrw" rel="noopener" target="_blank">YouTube</a>.</p>
<p><iframe width="560" height="315" src="https://www.youtube.com/embed/_dlKELBYgrw" frameborder="0" gesture="media" allowfullscreen></iframe></p>
]]></content:encoded>
							<wfw:commentRss>http://blog.bennymichielsen.be/2017/11/16/topconf-talinn-2017/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
							</item>
		<item>
		<title>PowerBI with .NET Core</title>
		<link>http://blog.bennymichielsen.be/2017/11/09/powerbi-with-net-core/</link>
				<comments>http://blog.bennymichielsen.be/2017/11/09/powerbi-with-net-core/#comments</comments>
				<pubDate>Thu, 09 Nov 2017 06:00:58 +0000</pubDate>
		<dc:creator><![CDATA[BennyM]]></dc:creator>
				<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[netcore]]></category>
		<category><![CDATA[powerbi]]></category>

		<guid isPermaLink="false">http://blog.bennymichielsen.be/?p=1426</guid>
				<description><![CDATA[In May I integrated PowerBI in a .NET Core and Angular application. In June a new version of PowerBI was released with an entire new way of getting reports to your customers, so I had to do the exercise again. The C# SDK only supports the .NET framework so I used the PowerBI API directly &#8230; <p class="link-more"><a href="http://blog.bennymichielsen.be/2017/11/09/powerbi-with-net-core/" class="more-link">Continue reading<span class="screen-reader-text"> "PowerBI with .NET Core"</span></a></p>]]></description>
								<content:encoded><![CDATA[<p>In May I integrated PowerBI in a .NET Core and Angular application. In June a new version of PowerBI was released with an entire new way of getting reports to your customers, so I had to do the exercise again. The C# SDK only supports the .NET framework so I used the PowerBI API directly to implement it. Although the API is <a href="https://msdn.microsoft.com/en-us/library/mt147898.aspx" rel="noopener" target="_blank">documented</a> I was only able to get it all working by reading it carefully and also following every step mentioned in <a href="https://blogs.msdn.microsoft.com/tsmatsuz/2017/07/14/power-bi-embed-report-in-app/" rel="noopener" target="_blank">this article</a>. The end result is great, Power BI offers a great reporting solution, getting it to run however was not a walk in the park. You can read about different scenarios on the <a href="https://powerbi.microsoft.com/en-us/documentation/powerbi-developer-what-can-you-do/" rel="noopener" target="_blank">official website</a>.</p>
<p>The ability to alter and publish reports without writing any code is awesome. In my current project we have an admin user that creates reports in PowerBI desktop, he uploads the report in our web application and we then publish it to each customer. They all have their own database and PowerBI allows you to basically change the connection string. In theory, it&#8217;s mentioned on the PowerBI site, we could also allow the customers to modify the published report or create their own. A scenario which we currently don&#8217;t need but which I might investigate nonetheless.</p>
<p>This weekend I decided to take a look again at the C# SDK. It&#8217;s really just a small layer between the API and your application and you don&#8217;t really need it, but it&#8217;s the natural place to start looking around. Since it only targets the .NET framework I couldn&#8217;t use it in .NET core. I forked the project, modified the csproj files to target .NET Standard 2.0 and updated the packages that were referenced. Zero warnings, zero errors. Not bad for a conversion!</p>
<p>The only thing that is different from the official samples is the way to get a token to call functions in the API. The official samples use UserPasswordCredentials which is not available. So as <a href="https://github.com/Microsoft/PowerBI-CSharp/issues/116#issuecomment-334914446" rel="noopener" target="_blank">another Github user mentioned</a> you need to do the heavy lifting yourself.</p>
<pre lang="csharp">
private async Task<TokenCredentials> GetAccessToken()
{
    using (HttpClient client = new HttpClient())
    {
        string tenantId = "";
        var tokenEndpoint = "";
        var accept = "application/json";
        var userName = "";
        var password = "";
        var clientId = "";

        client.DefaultRequestHeaders.Add("Accept", accept);
        string postBody = null;

        postBody = $@"resource=https%3A%2F%2Fanalysis.windows.net/powerbi/api
                        &client_id={clientId}
                        &grant_type=password
                        &username={userName}
                        &password={password}
                        &scope=openid";

        var tokenResult = await client.PostAsync(tokenEndpoint, new StringContent(postBody, Encoding.UTF8, "application/x-www-form-urlencoded"));
        tokenResult.EnsureSuccessStatusCode();
        var tokenData = await tokenResult.Content.ReadAsStringAsync();

        JObject parsedTokenData = JObject.Parse(tokenData);

        var token = parsedTokenData["access_token"].Value<string>();
        return new TokenCredentials(token, "Bearer");
    }
}
</pre>
<p>Once you have the token you can use the SDK as is.</p>
<pre lang="csharp">
    var tokenCredentials = await GetAccessToken();

    using (var powerBiclient = new PowerBIClient(new Uri("https://api.powerbi.com/"), tokenCredentials))
    {
        var reports = powerBiclient.Groups.GetGroups();
    }
</pre>
<p>I&#8217;ve pushed the code to <a href="https://github.com/BennyM/PowerBI-CSharp" rel="noopener" target="_blank">GitHub</a> and published it as a <a href="https://www.nuget.org/packages/PowerBI.Api/" rel="noopener" target="_blank">NuGet package</a>.</p>
]]></content:encoded>
							<wfw:commentRss>http://blog.bennymichielsen.be/2017/11/09/powerbi-with-net-core/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
							</item>
		<item>
		<title>Auditing with EF Core and Sql Server &#8211; Part 1: Temporal tables</title>
		<link>http://blog.bennymichielsen.be/2017/11/07/auditing-with-ef-core-and-sql-server-part-1/</link>
				<comments>http://blog.bennymichielsen.be/2017/11/07/auditing-with-ef-core-and-sql-server-part-1/#comments</comments>
				<pubDate>Tue, 07 Nov 2017 06:00:44 +0000</pubDate>
		<dc:creator><![CDATA[BennyM]]></dc:creator>
				<category><![CDATA[Software Development]]></category>
		<category><![CDATA[efcore]]></category>
		<category><![CDATA[sql]]></category>

		<guid isPermaLink="false">http://blog.bennymichielsen.be/?p=1413</guid>
				<description><![CDATA[It&#8217;s part of a lot of projects in which I&#8217;m involved. Keeping track of data that is changed, when the change occurred and, the most important part, who made the change. Apart from tracking down unauthorised changes it also helps when users claim they didn&#8217;t make a change. They tend to forget changes they made. &#8230; <p class="link-more"><a href="http://blog.bennymichielsen.be/2017/11/07/auditing-with-ef-core-and-sql-server-part-1/" class="more-link">Continue reading<span class="screen-reader-text"> "Auditing with EF Core and Sql Server &#8211; Part 1: Temporal tables"</span></a></p>]]></description>
								<content:encoded><![CDATA[<p>It&#8217;s part of a lot of projects in which I&#8217;m involved. Keeping track of data that is changed, when the change occurred and, the most important part, who made the change. Apart from tracking down unauthorised changes it also helps when users claim they didn&#8217;t make a change. They tend to forget changes they made. It&#8217;s a recurring requirement, but most of the time it&#8217;s there without the need for any further features. I&#8217;ve never had to create a diff screen or the like. We just need to keep track of all the changes to be on the safe side.</p>
<p>Most of the time you will see this being implemented with an interface that has to be implemented by your entities. The IAuditable interface with ModifiedByUser and ModifiedDate. It&#8217;s not that hard to implement and there are plenty of examples out there. Entity Framework has all the info you need, you can even get access to the old and new values of the properties and log them as well. </p>
<p>A quick Google search shows you how others are doing it, like <a href="https://stackoverflow.com/questions/26355486/entity-framework-6-audit-track-changes" rel="noopener" target="_blank">here</a> or even <a href="https://github.com/zzzprojects/EntityFramework-Plus/wiki/EF-Audit-%7C-Entity-Framework-Audit-Trail-Context-and-Track-Changes" rel="noopener" target="_blank">a library that keeps track</a> of it. It&#8217;s not that hard to roll your own implementation and you&#8217;ll learn more about EF in the process of implementing it.</p>
<p>I always consider it to be noise. It is a cross cutting concern showing up in all your entities and then there is the additional code in the dbcontext which needs to look at the changed entities and their properties. For my current project I wanted to look at it from a different angle and keep everything out of my entities and if possible the DbContext.</p>
<p>I&#8217;m using SQL Azure (or SQL 2016) and had read about <a href="https://docs.microsoft.com/en-us/sql/relational-databases/tables/temporal-table-usage-scenarios" rel="noopener" target="_blank">temporal tables</a> last year and it seemed this would be a perfect fit. SQL server can automatically insert the validity date of data and their value at the time in a history table. </p>
<p><a href="http://blog.bennymichielsen.be/wp-content/uploads/2017/11/Screen-Shot-2017-11-01-at-10.31.37.png"><img src="http://blog.bennymichielsen.be/wp-content/uploads/2017/11/Screen-Shot-2017-11-01-at-10.31.37-300x143.png" alt="" width="300" height="143" class="aligncenter size-medium wp-image-1416" srcset="http://blog.bennymichielsen.be/wp-content/uploads/2017/11/Screen-Shot-2017-11-01-at-10.31.37-300x143.png 300w, http://blog.bennymichielsen.be/wp-content/uploads/2017/11/Screen-Shot-2017-11-01-at-10.31.37.png 536w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>
<p>When enabling it on a table you need to add two columns for the validity period and the rest is taken care of by SQL Server. After inserting one record in the Products table, it will contain one row and its history table will be empty.</p>
<p><a href="http://blog.bennymichielsen.be/wp-content/uploads/2017/11/Screen-Shot-2017-11-01-at-10.34.10.png"><img src="http://blog.bennymichielsen.be/wp-content/uploads/2017/11/Screen-Shot-2017-11-01-at-10.34.10-300x33.png" alt="" width="300" height="33" class="aligncenter size-medium wp-image-1418" srcset="http://blog.bennymichielsen.be/wp-content/uploads/2017/11/Screen-Shot-2017-11-01-at-10.34.10-300x33.png 300w, http://blog.bennymichielsen.be/wp-content/uploads/2017/11/Screen-Shot-2017-11-01-at-10.34.10-768x85.png 768w, http://blog.bennymichielsen.be/wp-content/uploads/2017/11/Screen-Shot-2017-11-01-at-10.34.10.png 778w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>
<p>If I then issue an update statement, I get one row in the products table and one in its history table.</p>
<p><a href="http://blog.bennymichielsen.be/wp-content/uploads/2017/11/Screen-Shot-2017-11-01-at-10.37.27.png"><img src="http://blog.bennymichielsen.be/wp-content/uploads/2017/11/Screen-Shot-2017-11-01-at-10.37.27-300x70.png" alt="" width="300" height="70" class="aligncenter size-medium wp-image-1419" srcset="http://blog.bennymichielsen.be/wp-content/uploads/2017/11/Screen-Shot-2017-11-01-at-10.37.27-300x70.png 300w, http://blog.bennymichielsen.be/wp-content/uploads/2017/11/Screen-Shot-2017-11-01-at-10.37.27-768x179.png 768w, http://blog.bennymichielsen.be/wp-content/uploads/2017/11/Screen-Shot-2017-11-01-at-10.37.27.png 774w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>
<p>So far so good, we get an automatic history log. I was concerned that if I would add a column to the source table I would have to create an update to the corresponding history table but that is also handled by SQL Server. Migrations would just work. There are some restrictions however, as cascading deletes are no longer possible and would need to be handled by the application. You can find more limitations <a href="https://docs.microsoft.com/en-us/sql/relational-databases/tables/temporal-table-considerations-and-limitations" rel="noopener" target="_blank">here</a>.</p>
<p>To enable temporal tables on all my entities I created a couple of extension methods and added a migration to my code base.</p>
<pre lang="csharp">
public partial class EnableTemporalTable : Migration
{
    private string schemaName = "Logging";
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.Sql($"CREATE SCHEMA {schemaName}");
        var entityTypes = base.TargetModel.GetEntityTypes();
        foreach (var entityType in entityTypes)
        {
            migrationBuilder.AddAsTemporalTable(entityType, schemaName);
        }
    }

    protected override void Down(MigrationBuilder migrationBuilder)
    {
        var entityTypes = base.TargetModel.GetEntityTypes();
        foreach (var entityType in entityTypes)
        {
            migrationBuilder.RemoveAsTemporalTable(entityType, schemaName);
        }
        migrationBuilder.Sql($"DROP SCHEMA {schemaName}");
    }
}
</pre>
<p>Note that I&#8217;m iterating all entities. If you have a many to many relationship you will have to model it as an association entity to have it also gain the temporal features.</p>
<pre lang="csharp">
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;

public static class EnableTemporalDataOnTable
{
    public static void AddAsTemporalTable(this MigrationBuilder migrationBuilder, IEntityType entityType, string temporalScheme, string temporalTableName)
    {
        var tableName = entityType.Relational().TableName;
        var schemaName = entityType.Relational().Schema ?? "dbo";
        migrationBuilder.Sql($@"
                    IF NOT EXISTS (SELECT * FROM sys.[tables] t INNER JOIN sys.schemas s ON s.schema_id = t.schema_id WHERE t.name = '{tableName}' AND temporal_type = 2 and s.name = '{schemaName}')
                    BEGIN
                        ALTER TABLE {schemaName}.{tableName}   
                        ADD  ValidFrom datetime2 (2) GENERATED ALWAYS AS ROW START HIDDEN    
                                constraint DF_{tableName}_ValidFrom DEFAULT DATEADD(second, -1, SYSUTCDATETIME())  
                            , ValidTo datetime2 (2)  GENERATED ALWAYS AS ROW END HIDDEN     
                                constraint DF_{tableName}_ValidTo DEFAULT '9999.12.31 23:59:59.99'  
                            , PERIOD FOR SYSTEM_TIME (ValidFrom, ValidTo);   

                        ALTER TABLE {schemaName}.{tableName}    
                        SET (SYSTEM_VERSIONING = ON (HISTORY_TABLE = {temporalScheme}.{temporalTableName})); 
                    END
                ");

    }

    public static void AddAsTemporalTable(this MigrationBuilder migrationBuilder, IEntityType entityType, string temporalScheme)
    {
        var tableName = entityType.Relational().TableName;
        AddAsTemporalTable(migrationBuilder, entityType, temporalScheme, tableName);
    }

    public static void RemoveAsTemporalTable(this MigrationBuilder migrationBuilder, IEntityType entityType, string temporalScheme, string temporalTableName)
    {
        var tableName = entityType.Relational().TableName;
        var schemaName = entityType.Relational().Schema ?? "dbo"; 
        string alterStatement = $@"ALTER TABLE {tableName} SET (SYSTEM_VERSIONING = OFF);";
        migrationBuilder.Sql(alterStatement);
        alterStatement = $@"ALTER TABLE {tableName} DROP PERIOD FOR SYSTEM_TIME";
        migrationBuilder.Sql(alterStatement);
        alterStatement = $@"ALTER TABLE {tableName} DROP DF_{tableName}_SysStart, DF_{tableName}_SysEnd";
        migrationBuilder.Sql(alterStatement);
        alterStatement = $@"ALTER TABLE {tableName} DROP COLUMN SysStartTime, COLUMN SysEndTime";
        migrationBuilder.Sql(alterStatement);
        alterStatement = $@"DROP TABLE {temporalScheme}.{temporalTableName}";
        migrationBuilder.Sql(alterStatement);
    }

    public static void RemoveAsTemporalTable(this MigrationBuilder migrationBuilder, IEntityType entityType, string temporalScheme)
    {
        var tableName = entityType.Relational().TableName;
        RemoveAsTemporalTable(migrationBuilder, entityType, temporalScheme, tableName);
    }
}
</pre>
<p>This is largely based on <a href="https://intellitect.com/updating-sql-database-use-temporal-tables-entity-framework-migration/" rel="noopener" target="_blank">this blog post</a>. I just adapted it to be a bit more generic. If I would create a migration for a new table I could just call the extension method and have it temporal in one go.</p>
<p>But there was still one missing piece. Who made the change? I have no property on my entities to store this information and thus no column in the table or history table to store that info. In one of the first versions of <a href="https://docs.microsoft.com/en-us/sql/relational-databases/tables/temporal-table-usage-scenarios" rel="noopener" target="_blank">the article on the MSDN website</a> that introduces temporal tables it was mentioned that you could track the user, but that reference has since been deleted. So custom code is necessary. I didn&#8217;t want to add the property to each of my entities so I used a new feature in EF core called <a href="https://docs.microsoft.com/en-us/ef/core/modeling/shadow-properties" rel="noopener" target="_blank">shadow properties</a>. Funny enough, the example on the MSDN site is about auditing.</p>
<p>So I created an override for the OnModelCreating and the SaveChanges and SaveChangesAsync method of the DbContext. So not completely honouring my initial goal to keep it out of my application code.</p>
<pre lang="csharp">
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    foreach (var entityType in modelBuilder.Model.GetEntityTypes())
    {
        modelBuilder.Entity(entityType.ClrType).Property<string>("ModifiedBy");
    }
}
</pre>
<p>The SaveChanges and SaveChangesAsync would call into this method and the principal was injected in the constructor of the DbContext.</p>
<pre lang="csharp">
public void SetModifiedInformation()
{
    var modifiedByEntries = ChangeTracker.Entries()
        .Where(e => e.State == EntityState.Added || e.State == EntityState.Modified || e.State == EntityState.Deleted);

    foreach (EntityEntry entry in modifiedByEntries)
    {
        entry.Property("ModifiedBy").CurrentValue = this.principal?.Identity?.Name;
    }
}

public override int SaveChanges()
{
    SetModifiedInformation();
    return base.SaveChanges();
}

public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken())
{
    SetModifiedInformation();
    return await base.SaveChangesAsync(cancellationToken);
}
</pre>
<p>This worked, but one scenario is now missing in this solution. We know who created or updated a row, but with a delete we lose the value in the ModifiedBy property. The deleted row is copied from the source table to the history table. I considered the ultimate hack: create an instead of trigger on the table and issue an update and then a delete but luckily SQL server prevented me from even trying it. Instead of triggers are not possible with table that is temporal. I considered adding a separate table to keep track of who deleted a certain row, but this would again introduce more code than I wanted and clutter the codebase. I could introduce soft deletes so that a delete will become an update but that just opens another can of worms.</p>
<p>So I went back to the drawing board to find a better solution, which turned out to be a blast from the past combined with a new feature in SQL server 2016. But that&#8217;s for next time.</p>
]]></content:encoded>
							<wfw:commentRss>http://blog.bennymichielsen.be/2017/11/07/auditing-with-ef-core-and-sql-server-part-1/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
							</item>
		<item>
		<title>Migrating databases with EF Core 2.0 during a VSTS release</title>
		<link>http://blog.bennymichielsen.be/2017/10/31/migrating-databases-with-ef-core-2-0-during-a-vsts-release/</link>
				<comments>http://blog.bennymichielsen.be/2017/10/31/migrating-databases-with-ef-core-2-0-during-a-vsts-release/#respond</comments>
				<pubDate>Tue, 31 Oct 2017 06:00:07 +0000</pubDate>
		<dc:creator><![CDATA[BennyM]]></dc:creator>
				<category><![CDATA[Software Development]]></category>
		<category><![CDATA[efcore]]></category>
		<category><![CDATA[vsts]]></category>

		<guid isPermaLink="false">http://blog.bennymichielsen.be/?p=1406</guid>
				<description><![CDATA[A while ago I wrote down how to migrate a database using the default tooling with EF Core 1.1. With 2.0 being released last August it was finally time to upgrade projects on which I&#8217;m working to the latest bits. A reader had already reported that the same approach as used with 1.1 no longer &#8230; <p class="link-more"><a href="http://blog.bennymichielsen.be/2017/10/31/migrating-databases-with-ef-core-2-0-during-a-vsts-release/" class="more-link">Continue reading<span class="screen-reader-text"> "Migrating databases with EF Core 2.0 during a VSTS release"</span></a></p>]]></description>
								<content:encoded><![CDATA[<p>A while ago I wrote down h<a href="http://blog.bennymichielsen.be/2017/08/01/migrating-databases-with-ef-core-during-a-vsts-release/" rel="noopener" target="_blank">ow to migrate a database</a> using the default tooling with EF Core 1.1. With 2.0 being released last August it was finally time to upgrade projects on which I&#8217;m working to the latest bits. A reader had already reported that the same approach as used with 1.1 no longer worked for EF Core 2.0.</p>
<p>Again I ran the update database command with the verbose option and I saw that the command itself has not changed. What has changed however is the location of EF.dll. Even when forcing the package restore to not use any caching and explicitly stating where the packages had to be installed, EF.dll just would not show up. It is however located (at least on my Mac) at /usr/local/share/dotnet/sdk/NuGetFallbackFolder/microsoft.entityframeworkcore.tools.dotnet/2.0.0/tools/netcoreapp2.0/ef.dll.</p>
<p>I tried for an hour or two to get this file in a zip archive on Windows and on macOS. The easy way out would be to just find the dll and add it to source control. Of course I went for another solution: download the EF.dll during a release and use it to update the databases.</p>
<p>I edited the release definition of VSTS and in my first attempt I tried to use the package management task which you get when you install <a href="https://marketplace.visualstudio.com/items?itemName=ms.feed" target="_blank" rel="noopener">this extension</a>. Unfortunately this is not meant to be used to download public packages from the NuGet servers.</p>
<p>Second attempt was to use the <a href="https://marketplace.visualstudio.com/items?itemName=automagically.DownloadFile#overview" target="_blank" rel="noopener">Download file task</a>. It was not able to download <a href="https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.Tools.DotNet/" target="_blank" rel="noopener">the NuGet package I needed</a> giving me a 404 error.</p>
<p>So when everything fails, Powershell will fix it. With just a single line I was able to download the NuGet package containing EF.dll.</p>
<p><a href="http://blog.bennymichielsen.be/wp-content/uploads/2017/10/Screen-Shot-2017-10-26-at-20.55.22.png"><img class="aligncenter size-medium wp-image-1407" src="http://blog.bennymichielsen.be/wp-content/uploads/2017/10/Screen-Shot-2017-10-26-at-20.55.22-300x92.png" alt="" width="300" height="92" srcset="http://blog.bennymichielsen.be/wp-content/uploads/2017/10/Screen-Shot-2017-10-26-at-20.55.22-300x92.png 300w, http://blog.bennymichielsen.be/wp-content/uploads/2017/10/Screen-Shot-2017-10-26-at-20.55.22-768x235.png 768w, http://blog.bennymichielsen.be/wp-content/uploads/2017/10/Screen-Shot-2017-10-26-at-20.55.22-1024x313.png 1024w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>
<p>I used an inline script, but you could just create a script and add it to source control so you can use variables for the package name.</p>
<pre lang="bash">wget "https://www.nuget.org/api/v2/package/Microsoft.EntityFrameworkCore.Tools.DotNet/2.0.0" -outfile "EF.nupkg"
</pre>
<p>Then I extract all the files, since the build output contains one or more zip files and a nupkg file is also just a zip archive. My sample project just contained one zip.</p>
<p><a href="http://blog.bennymichielsen.be/wp-content/uploads/2017/10/Screen-Shot-2017-10-26-at-21.01.12.png"><img class="aligncenter size-medium wp-image-1408" src="http://blog.bennymichielsen.be/wp-content/uploads/2017/10/Screen-Shot-2017-10-26-at-21.01.12-300x80.png" alt="" width="300" height="80" srcset="http://blog.bennymichielsen.be/wp-content/uploads/2017/10/Screen-Shot-2017-10-26-at-21.01.12-300x80.png 300w, http://blog.bennymichielsen.be/wp-content/uploads/2017/10/Screen-Shot-2017-10-26-at-21.01.12-768x205.png 768w, http://blog.bennymichielsen.be/wp-content/uploads/2017/10/Screen-Shot-2017-10-26-at-21.01.12-1024x273.png 1024w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>
<p>Then move the EF.dll to the location where the assembly resides containing the DbContext and migrations. The final step is to execute the update command.</p>
<p><a href="http://blog.bennymichielsen.be/wp-content/uploads/2017/10/Screen-Shot-2017-10-26-at-21.02.46.png"><img class="aligncenter size-medium wp-image-1409" src="http://blog.bennymichielsen.be/wp-content/uploads/2017/10/Screen-Shot-2017-10-26-at-21.02.46-300x75.png" alt="" width="300" height="75" srcset="http://blog.bennymichielsen.be/wp-content/uploads/2017/10/Screen-Shot-2017-10-26-at-21.02.46-300x75.png 300w, http://blog.bennymichielsen.be/wp-content/uploads/2017/10/Screen-Shot-2017-10-26-at-21.02.46-768x192.png 768w, http://blog.bennymichielsen.be/wp-content/uploads/2017/10/Screen-Shot-2017-10-26-at-21.02.46-1024x256.png 1024w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>
<pre lang="bash">mv ./tools/netcoreapp2.0/ef.dll ./
dotnet exec --depsfile migratetest20.deps.json  --runtimeconfig migratetest20.runtimeconfig.json ef.dll database update --assembly migratetest20.dll --startup-assembly migratetest20.dll
</pre>
<p>Migratetest20 was my test project.</p>
]]></content:encoded>
							<wfw:commentRss>http://blog.bennymichielsen.be/2017/10/31/migrating-databases-with-ef-core-2-0-during-a-vsts-release/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
							</item>
		<item>
		<title>Topconf Duesseldorf 2017</title>
		<link>http://blog.bennymichielsen.be/2017/10/12/topconf-duesseldorf-2017/</link>
				<comments>http://blog.bennymichielsen.be/2017/10/12/topconf-duesseldorf-2017/#respond</comments>
				<pubDate>Thu, 12 Oct 2017 05:00:09 +0000</pubDate>
		<dc:creator><![CDATA[BennyM]]></dc:creator>
				<category><![CDATA[Software Development]]></category>
		<category><![CDATA[bitcoin]]></category>
		<category><![CDATA[blockchain]]></category>
		<category><![CDATA[ethereum]]></category>

		<guid isPermaLink="false">http://blog.bennymichielsen.be/?p=1396</guid>
				<description><![CDATA[Last week I was fortunate enough to be part of Topconf Duesseldorf. It was the first time the conference was organized in Duesseldorf. My talk on blockchain technology and more specific on Bitcoin and Ethereum had been selected and together with 46 other speakers we would fill two days packed with sessions. I had changed &#8230; <p class="link-more"><a href="http://blog.bennymichielsen.be/2017/10/12/topconf-duesseldorf-2017/" class="more-link">Continue reading<span class="screen-reader-text"> "Topconf Duesseldorf 2017"</span></a></p>]]></description>
								<content:encoded><![CDATA[<p>Last week I was fortunate enough to be part of <a href="https://www.topconf.com/conference/duesseldorf-2017/index" target="_blank" rel="noopener">Topconf Duesseldorf</a>. It was the first time the conference was organized in Duesseldorf. My talk on blockchain technology and more specific on Bitcoin and Ethereum had been selected and together with 46 other speakers we would fill two days packed with sessions.</p>
<p><a href="http://blog.bennymichielsen.be/wp-content/uploads/2017/10/056-Benny-Michielsen.jpg"><img class="aligncenter size-medium wp-image-1397" src="http://blog.bennymichielsen.be/wp-content/uploads/2017/10/056-Benny-Michielsen-207x300.jpg" alt="" width="207" height="300" srcset="http://blog.bennymichielsen.be/wp-content/uploads/2017/10/056-Benny-Michielsen-207x300.jpg 207w, http://blog.bennymichielsen.be/wp-content/uploads/2017/10/056-Benny-Michielsen.jpg 689w" sizes="(max-width: 207px) 100vw, 207px" /></a></p>
<p>I had changed the abstract a little bit after reviewing the feedback from NDC and also removed parts of the presentation to fit it in 40 minutes. In the end though I did go over time, and with only 10 minutes between sessions I had to rush through the last part. Lessons learned for next month when I will be giving this talk at <a href="https://www.topconf.com/conference/topconf-tallinn-2017/index" target="_blank" rel="noopener">Topconf Talinn</a>.</p>
<blockquote class="twitter-tweet" data-lang="en">
<p lang="en" dir="ltr">Building a rock-paper-scissors-lizzard-spock with <a href="https://twitter.com/hashtag/etherium?src=hash&amp;ref_src=twsrc%5Etfw">#etherium</a> by <a href="https://twitter.com/bennymichielsen?ref_src=twsrc%5Etfw">@bennymichielsen</a> at <a href="https://twitter.com/TopconfDE?ref_src=twsrc%5Etfw">@topconfDE</a> <a href="https://t.co/Z91zD7pCMg">pic.twitter.com/Z91zD7pCMg</a></p>
<p>&mdash; dominik kundel ? (@DKundel) <a href="https://twitter.com/DKundel/status/915941027919351808?ref_src=twsrc%5Etfw">October 5, 2017</a></p></blockquote>
<p><script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script></p>
<p>There were a lot of questions during and after the talk so the audience was quite engaged, in fact the atmosphere of the entire conference was very amicable. The reviews which have been submitted for my session also reflect my own thoughts on how it went. At the time of writing this post my session got an average score of 4.29 / 5. The slides can be downloaded <a href="http://blog.bennymichielsen.be/wp-content/uploads/2017/10/Topconf_Duesseldorf-Blockchain.pdf">here</a> and the code of the DApp is available on <a href="https://github.com/BennyM/bigbangblockchaingame" rel="noopener" target="_blank">GitHub</a>. I&#8217;ve now written the game 3 times and it was also the first time I felt confident enough to let the attendees participate.</p>
<blockquote class="twitter-tweet" data-lang="en">
<p lang="en" dir="ltr"><a href="https://twitter.com/bennymichielsen?ref_src=twsrc%5Etfw">@bennymichielsen</a> talking about the <a href="https://twitter.com/hashtag/blockchain?src=hash&amp;ref_src=twsrc%5Etfw">#blockchain</a> at <a href="https://twitter.com/TopconfDE?ref_src=twsrc%5Etfw">@TopconfDE</a> <a href="https://t.co/7eVFRROv3X">pic.twitter.com/7eVFRROv3X</a></p>
<p>&mdash; Frank Mathy (@FrankMathy) <a href="https://twitter.com/FrankMathy/status/915937338668257280?ref_src=twsrc%5Etfw">October 5, 2017</a></p></blockquote>
<p><script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script></p>
<p>In the audience was also <a href="https://twitter.com/iamjoyclark" target="_blank" rel="noopener">Joy Clarck</a> who made a great summary.</p>
<blockquote class="twitter-tweet" data-lang="en">
<p dir="ltr" lang="en">Learning about Blockchain with <a href="https://twitter.com/bennymichielsen?ref_src=twsrc%5Etfw">@bennymichielsen</a> <a href="https://twitter.com/TopconfDE?ref_src=twsrc%5Etfw">@TopconfDE</a> <a href="https://twitter.com/hashtag/Sketchnote?src=hash&amp;ref_src=twsrc%5Etfw">#Sketchnote</a> <a href="https://t.co/gSqBUnyjSm">pic.twitter.com/gSqBUnyjSm</a></p>
<p>— Joy Clark (@iamjoyclark) <a href="https://twitter.com/iamjoyclark/status/915948750308302848?ref_src=twsrc%5Etfw">October 5, 2017</a></p></blockquote>
<p><script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script></p>
]]></content:encoded>
							<wfw:commentRss>http://blog.bennymichielsen.be/2017/10/12/topconf-duesseldorf-2017/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
							</item>
		<item>
		<title>Migrating databases with EF Core during a VSTS release</title>
		<link>http://blog.bennymichielsen.be/2017/08/01/migrating-databases-with-ef-core-during-a-vsts-release/</link>
				<comments>http://blog.bennymichielsen.be/2017/08/01/migrating-databases-with-ef-core-during-a-vsts-release/#comments</comments>
				<pubDate>Tue, 01 Aug 2017 03:00:42 +0000</pubDate>
		<dc:creator><![CDATA[BennyM]]></dc:creator>
				<category><![CDATA[Software Development]]></category>
		<category><![CDATA[efcore]]></category>
		<category><![CDATA[vsts]]></category>

		<guid isPermaLink="false">http://blog.bennymichielsen.be/?p=1368</guid>
				<description><![CDATA[I wanted to migrate databases during a release. The default way of doing this is to run code when the application starts. Great for little demo projects but not when you are releasing a real app to production. When you are pushing a new version to production and the migration fails the release should fail, &#8230; <p class="link-more"><a href="http://blog.bennymichielsen.be/2017/08/01/migrating-databases-with-ef-core-during-a-vsts-release/" class="more-link">Continue reading<span class="screen-reader-text"> "Migrating databases with EF Core during a VSTS release"</span></a></p>]]></description>
								<content:encoded><![CDATA[<p>I wanted to migrate databases during a release. The default way of doing this is to run code when the application starts. Great for little demo projects but not when you are releasing a real app to production. When you are pushing a new version to production and the migration fails the release should fail, alarms should go off etc. With the &#8220;old&#8221; Entity Framework I usually wrapped the migration code in a console application. I packaged it alongside the other code and then executed an additional release step to execute the migrations. Since I&#8217;ve been using .NET Core on my latest projects I wanted to see if I could use all the default tooling.</p>
<p>If you run the update command with the verbose option you will see that &#8220;dotnet exec&#8221; is called using &#8220;EF.dll&#8221; together with a bunch of other options. This is the behaviour I want to replicate during a release.</p>
<pre lang="bash">
dotnet ef database update -v
</pre>
<p>The first thing to figure out is where to find &#8220;EF.dll&#8221;. This is of course in a NuGet package. By default they are downloaded in your user&#8217;s home folder. I was not able to figure out a way to just grab it from there using a hosted build agent. However by modifying the restore command I can specify where the packages need to be downloaded.</p>
<pre lang="bash">
dotnet restore --packages /my/location
</pre>
<p><a href="http://blog.bennymichielsen.be/wp-content/uploads/2017/07/restore-package-location.png" target="_blank"><img src="http://blog.bennymichielsen.be/wp-content/uploads/2017/07/restore-package-location-300x219.png" alt="" width="300" height="219" class="aligncenter size-medium wp-image-1371" srcset="http://blog.bennymichielsen.be/wp-content/uploads/2017/07/restore-package-location-300x219.png 300w, http://blog.bennymichielsen.be/wp-content/uploads/2017/07/restore-package-location-768x562.png 768w, http://blog.bennymichielsen.be/wp-content/uploads/2017/07/restore-package-location.png 982w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>
<p>I then added an additional &#8220;Archive files&#8221; build step to my build definition. This step creates a zip file and adds it to the build artifacts staging directory. This means it will automatically be picked up with all the other deliverables.</p>
<p><a href="http://blog.bennymichielsen.be/wp-content/uploads/2017/07/archive-ef-dll.png" target="_blank"><img src="http://blog.bennymichielsen.be/wp-content/uploads/2017/07/archive-ef-dll-300x203.png" alt="" width="300" height="203" class="aligncenter size-medium wp-image-1372" srcset="http://blog.bennymichielsen.be/wp-content/uploads/2017/07/archive-ef-dll-300x203.png 300w, http://blog.bennymichielsen.be/wp-content/uploads/2017/07/archive-ef-dll-768x519.png 768w, http://blog.bennymichielsen.be/wp-content/uploads/2017/07/archive-ef-dll-1024x692.png 1024w, http://blog.bennymichielsen.be/wp-content/uploads/2017/07/archive-ef-dll.png 1648w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>
<p>Those are all the necessary changes for the build definition. Now the extra bits in the release definition. I need four additional steps, but it&#8217;s also important to select the correct agent. As I&#8217;ll be running .NET Core commands I need a VS2017 agent.</p>
<p><a href="http://blog.bennymichielsen.be/wp-content/uploads/2017/07/release-steps.png" target="_blank"><img src="http://blog.bennymichielsen.be/wp-content/uploads/2017/07/release-steps-300x72.png" alt="" width="300" height="72" class="aligncenter size-medium wp-image-1374" srcset="http://blog.bennymichielsen.be/wp-content/uploads/2017/07/release-steps-300x72.png 300w, http://blog.bennymichielsen.be/wp-content/uploads/2017/07/release-steps-768x185.png 768w, http://blog.bennymichielsen.be/wp-content/uploads/2017/07/release-steps-1024x247.png 1024w, http://blog.bennymichielsen.be/wp-content/uploads/2017/07/release-steps-2000x484.png 2000w, http://blog.bennymichielsen.be/wp-content/uploads/2017/07/release-steps.png 2006w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>
<p>The first step is to unarchive the archive which has the appsettings.json with the connectionstring, in my case it&#8217;s the output of a project which houses the web api and an Angular app, the other archive we need has the EF Core bits we need.</p>
<p><a href="http://blog.bennymichielsen.be/wp-content/uploads/2017/07/extract-files.png" target="_blank"><img src="http://blog.bennymichielsen.be/wp-content/uploads/2017/07/extract-files-300x117.png" alt="" width="300" height="117" class="aligncenter size-medium wp-image-1376" srcset="http://blog.bennymichielsen.be/wp-content/uploads/2017/07/extract-files-300x117.png 300w, http://blog.bennymichielsen.be/wp-content/uploads/2017/07/extract-files-768x300.png 768w, http://blog.bennymichielsen.be/wp-content/uploads/2017/07/extract-files-1024x399.png 1024w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>
<p>I then need the correct connectionstring, this is of course a variable in my release environment. The easiest way to replace the connectionstring in appsettings.json of the unarchived files of the web application is to <a href="https://github.com/colindembovsky/cols-agent-tasks/tree/master/Tasks/Tokenizer" target="_blank">use an extension of VSTS</a>. It&#8217;s a two step process, we first tokenize the file so the second step can find the placeholders.</p>
<p><a href="http://blog.bennymichielsen.be/wp-content/uploads/2017/07/tokenize.png" target="_blank"><img src="http://blog.bennymichielsen.be/wp-content/uploads/2017/07/tokenize-300x83.png" alt="" width="300" height="83" class="aligncenter size-medium wp-image-1377" srcset="http://blog.bennymichielsen.be/wp-content/uploads/2017/07/tokenize-300x83.png 300w, http://blog.bennymichielsen.be/wp-content/uploads/2017/07/tokenize-768x213.png 768w, http://blog.bennymichielsen.be/wp-content/uploads/2017/07/tokenize-1024x283.png 1024w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>
<p><a href="http://blog.bennymichielsen.be/wp-content/uploads/2017/07/replace-tokens.png" target="_blank"><img src="http://blog.bennymichielsen.be/wp-content/uploads/2017/07/replace-tokens-300x85.png" alt="" width="300" height="85" class="aligncenter size-medium wp-image-1378" srcset="http://blog.bennymichielsen.be/wp-content/uploads/2017/07/replace-tokens-300x85.png 300w, http://blog.bennymichielsen.be/wp-content/uploads/2017/07/replace-tokens-768x218.png 768w, http://blog.bennymichielsen.be/wp-content/uploads/2017/07/replace-tokens-1024x290.png 1024w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>
<p>The final step is to do the same command we execute on our development machine. The hard part is figuring out all the parameters. In my case the migrations (and all of the logic) is in a dll named: App.dll while the web application and the connectionstring is from another dll: App.Web.dll</p>
<pre lang="bash">
exec --depsfile App.Web.deps.json --runtimeconfig App.Web.runtimeconfig.json ef.dll database update --assembly App.dll --startup-assembly App.Web.dll --verbose --root-namespace MyAppNamespace
</pre>
<p><a href="http://blog.bennymichielsen.be/wp-content/uploads/2017/07/do-database-update.png" target="_blank"><img src="http://blog.bennymichielsen.be/wp-content/uploads/2017/07/do-database-update-300x81.png" alt="" width="300" height="81" class="aligncenter size-medium wp-image-1379" srcset="http://blog.bennymichielsen.be/wp-content/uploads/2017/07/do-database-update-300x81.png 300w, http://blog.bennymichielsen.be/wp-content/uploads/2017/07/do-database-update-768x208.png 768w, http://blog.bennymichielsen.be/wp-content/uploads/2017/07/do-database-update-1024x277.png 1024w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>
<p>And that&#8217;s it, now the database is upgraded during a release.</p>
]]></content:encoded>
							<wfw:commentRss>http://blog.bennymichielsen.be/2017/08/01/migrating-databases-with-ef-core-during-a-vsts-release/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
							</item>
		<item>
		<title>Managing settings for an Angular app with VSTS</title>
		<link>http://blog.bennymichielsen.be/2017/07/27/managing-settings-for-an-angular-app-with-vsts/</link>
				<comments>http://blog.bennymichielsen.be/2017/07/27/managing-settings-for-an-angular-app-with-vsts/#comments</comments>
				<pubDate>Thu, 27 Jul 2017 04:39:21 +0000</pubDate>
		<dc:creator><![CDATA[BennyM]]></dc:creator>
				<category><![CDATA[Software Development]]></category>
		<category><![CDATA[angular]]></category>
		<category><![CDATA[vsts]]></category>

		<guid isPermaLink="false">http://blog.bennymichielsen.be/?p=1344</guid>
				<description><![CDATA[Recently I needed to have client side settings in an Angular app. My app had to call some 3rd party webservices and their location was different per environment (test, QA and production), I also had to configure a couple of parameters that were necessary when calling them. There&#8217;s support for this in Angular using &#8220;environments&#8221;. &#8230; <p class="link-more"><a href="http://blog.bennymichielsen.be/2017/07/27/managing-settings-for-an-angular-app-with-vsts/" class="more-link">Continue reading<span class="screen-reader-text"> "Managing settings for an Angular app with VSTS"</span></a></p>]]></description>
								<content:encoded><![CDATA[<p>Recently I needed to have client side settings in an Angular app. My app had to call some 3rd party webservices and their location was different per environment (test, QA and production), I also had to configure a couple of parameters that were necessary when calling them.</p>
<p>There&#8217;s support for this in Angular using &#8220;environments&#8221;. If you scaffold a new Angular app with angular-cli you&#8217;ll get a folder &#8220;Environments&#8221;.</p>
<p><a href="http://blog.bennymichielsen.be/wp-content/uploads/2017/06/Screen-Shot-2017-06-24-at-08.38.49.png"><img class="size-medium wp-image-1345 aligncenter" src="http://blog.bennymichielsen.be/wp-content/uploads/2017/06/Screen-Shot-2017-06-24-at-08.38.49-300x104.png" alt="environments" width="300" height="104" srcset="http://blog.bennymichielsen.be/wp-content/uploads/2017/06/Screen-Shot-2017-06-24-at-08.38.49-300x104.png 300w, http://blog.bennymichielsen.be/wp-content/uploads/2017/06/Screen-Shot-2017-06-24-at-08.38.49.png 456w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>
<p>These files can be used while building the application. <a href="https://github.com/angular/angular-cli/wiki/build" target="_blank" rel="noopener">Specifying the environment</a> will bundle the environment specific file together with the rest of your application. Which is great but I don&#8217;t want to rebuild the application when I go from test to QA and finally to production. Typically settings are changed when deploying to an environment, at least that&#8217;s what I usually do with my .NET projects.</p>
<p>Trying to have one unified way of handling the settings gives two challenges: how to bootstrap the Angular app with dynamic settings and how to manage these during deployment.</p>
<p>I added a client-config.json file in my asset folder to contain all the settings and the values which were correct during development.</p>
<p><a href="http://blog.bennymichielsen.be/wp-content/uploads/2017/07/Screen-Shot-2017-07-21-at-14.47.16.png"><img class="aligncenter size-full wp-image-1356" src="http://blog.bennymichielsen.be/wp-content/uploads/2017/07/Screen-Shot-2017-07-21-at-14.47.16.png" alt="client-config.json" width="380" height="316" srcset="http://blog.bennymichielsen.be/wp-content/uploads/2017/07/Screen-Shot-2017-07-21-at-14.47.16.png 380w, http://blog.bennymichielsen.be/wp-content/uploads/2017/07/Screen-Shot-2017-07-21-at-14.47.16-300x249.png 300w" sizes="(max-width: 380px) 100vw, 380px" /></a></p>
<p>This file needs to be downloaded before most of the application actually starts so I added a settings provider.</p>
<pre lang="javascript">
import { Http } from '@angular/http';
import { Injectable } from '@angular/core';

@Injectable()
export class SettingsProvider {

  private config : any;

  constructor(private http: Http) {
  }

  public loadConfig() : Promise<any>{
    return this.http.get("assets/client-config.json")
      .map(res => res.json())
      .toPromise()
      .then(settings => this.config = settings);
  }

  public get configuration(): any {
    return this.config;
  }
}
</pre>
<p>Then in my app.module.ts I add a new function to load the configuration.</p>
<pre lang="javascript">
export function init(settingsProvider: SettingsProvider) {
  return () => settingsProvider.loadConfig();
}
</pre>
<p>I also changed the NgModule declaration to include</p>
<pre lang="javascript">
  providers: [{
    'provide': APP_INITIALIZER,
    'useFactory': init,
    'deps': [SettingsProvider],
    'multi': true
  },
  SettingsProvider]
</pre>
<p>The crux here is the APP_INITIALIZER token which Angular provides to run logic before the application starts. You can read more about it <a href="https://hackernoon.com/hook-into-angular-initialization-process-add41a6b7e" target="_blank">here</a> and <a href="https://gillespie59.github.io/2016/12/04/angular2-code-before-rendering.html" target="_blank">here</a>.</p>
<p>With the client side now done, the application still needs to get the correct values when the application is pushed to different environments. This is the easy part as VSTS has support for file transforms and variable substitution. I just add my client-config.json to the list of files that need to be changed. VSTS will <a href="https://www.visualstudio.com/en-us/docs/build/steps/transforms-variable-substitution#jsonvarsubs" target="_blank">replace any variable</a> it finds that can be matched with variables defined for the environment where I deploy.</p>
<p><a href="http://blog.bennymichielsen.be/wp-content/uploads/2017/07/vsts-config.png"><img src="http://blog.bennymichielsen.be/wp-content/uploads/2017/07/vsts-config-1024x331.png" alt="VSTS Config" width="525" height="170" class="size-large wp-image-1361" srcset="http://blog.bennymichielsen.be/wp-content/uploads/2017/07/vsts-config-1024x331.png 1024w, http://blog.bennymichielsen.be/wp-content/uploads/2017/07/vsts-config-300x97.png 300w, http://blog.bennymichielsen.be/wp-content/uploads/2017/07/vsts-config-768x248.png 768w" sizes="(max-width: 525px) 100vw, 525px" /></a></p>
<p>The client-config.json is also added to the list of files the Angular build needs to pick up.</p>
<pre lang="javascript">
 "apps": [
    {
      "root": "src",
      "outDir": "../wwwroot",
      "assets": [
        "assets",
        "favicon.ico",
        "client-config.json"
      ],
      ....
    }]
</pre>
<p>The end result is a single way to manage environment specific settings for my .NET Core and Angular applications.</p>
]]></content:encoded>
							<wfw:commentRss>http://blog.bennymichielsen.be/2017/07/27/managing-settings-for-an-angular-app-with-vsts/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
							</item>
	</channel>
</rss>
