Compiled Experience Windows Platform Development http://compiledexperience.com en Tue, 19 Mar 2019 08:31:51 +0000 Tue, 19 Mar 2019 08:31:51 +0000 Guarding against N+1 issues in GraphQL <p>The <strong>N+1 query problem</strong> is a common one to encounter during software development, particularly with ORMs (Object Relational Mappers) and their capabilities around lazy loading. A quick example looks like</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">orders</span> <span class="p">=</span> <span class="nf">GetOrders</span><span class="p">();</span> <span class="k">foreach</span><span class="p">(</span><span class="kt">var</span> <span class="n">order</span> <span class="k">in</span> <span class="n">orders</span><span class="p">)</span> <span class="p">{</span> <span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="s">$"</span><span class="p">{</span><span class="n">order</span><span class="p">.</span><span class="n">Customer</span><span class="p">.</span><span class="n">Name</span><span class="p">}</span><span class="s"> made an order on </span><span class="p">{</span><span class="n">order</span><span class="p">.</span><span class="n">CreatedOn</span><span class="p">}</span><span class="s">"</span><span class="p">);</span> <span class="p">}</span> </code></pre></div></div> <p>Unless you’re careful, the lazy loading of the <code class="highlighter-rouge">Customer</code> of the <code class="highlighter-rouge">Order</code> results in a database query, for 100 orders this would result in 101 database calls, one per <code class="highlighter-rouge">Customer</code> and one extra for the orders (hence the name N+1).</p> <p>I won’t go into the ways we can solve this in ORMs as this is a well documented problem with a myriad of approaches to avoid it.</p> <h2 id="graphql-and-n1">GraphQL and N+1</h2> <p>When we look at a typical GraphQL query we can see the makings of the same problem.</p> <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>query { orders { createdOn customer { name } } } </code></pre></div></div> <p>Whether the above query results in N+1 database queries is completely up to the the implementation of the resolvers. Most GraphQL server frameworks support the idea of a <code class="highlighter-rouge">DataLoader</code>. A Dataloader allows you to batch the <code class="highlighter-rouge">Customer</code> requests into a single query and put the correct <code class="highlighter-rouge">Customer</code> into the correct location of the results. For better examples you can view the documentation for <a href="https://hotchocolate.io/docs/dataloaders">Hot Chocolate</a>, a popular .NET GraphQL server framework. This only works when the underlying data source supports a performant batch operation (in these case getting a list of customers based on a list of ids).</p> <h2 id="when-dataloader-wont-work">When DataLoader won’t work</h2> <p>Sometimes however this batch operation isn’t supported and we’re left with our N+1 performance problem, what can we do?</p> <p>Let’s assume our Orders and Customers data live in different microservices and that Customers microservice doesn’t support a batch operation for requesting a list of Customers.</p> <p>In that case a query like the above one wouldn’t be performant, resulting in N requests to the underlying Customer microservice, however a query like the following would only result in a single call.</p> <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>query { order("b3JkZXI6NDI=") { createdOn customer { name } } } </code></pre></div></div> <p>So how do we ensure one is valid, but one is invalid? The easiest way would be to define different <code class="highlighter-rouge">Order</code> types in our schema, one that has <code class="highlighter-rouge">customer</code> field and one doesn’t and never expose the former in a list field. While it works it would cause a long term maintenance problem as we struggle to keep these types in sync and doesn’t create a particularly nice graph.</p> <p>Instead we’re going to play with the <a href="https://hotchocolate.io/docs/validation-rule">validation rules</a> feature of Hot Chocolate. We’ll create a rule that the <code class="highlighter-rouge">customer</code> field can only be included in a query where none of its parent fields are a list. This would ensure the latter query is valid while the former is invalid.</p> <p>One really nice feature about validation rules are that they’re done during the parsing of the query document. This means the validation result can be cached along with the parsing result. This way if you’re sending constant queries (where only the variables are different) then the validation rule won’t be executed that often.</p> <h2 id="creating-the-directive">Creating the Directive</h2> <p>First we need to create a directive, these function in much the same way as C# attributes, a way to attach metadata to our GraphQL schema that other code can introspect and make use of. In this case we’ll define an <code class="highlighter-rouge">includeOnce</code>.</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">IncludeOnceDirectiveType</span> <span class="p">:</span> <span class="n">DirectiveType</span> <span class="p">{</span> <span class="k">protected</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">Configure</span><span class="p">(</span><span class="n">IDirectiveTypeDescriptor</span> <span class="n">descriptor</span><span class="p">)</span> <span class="p">{</span> <span class="n">descriptor</span><span class="p">.</span><span class="nf">Name</span><span class="p">(</span><span class="s">"includeOnce"</span><span class="p">);</span> <span class="n">descriptor</span><span class="p">.</span><span class="nf">Location</span><span class="p">(</span><span class="n">DirectiveLocation</span><span class="p">.</span><span class="n">FieldDefinition</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> </code></pre></div></div> <p>This directive doesn’t have any behavior and simply functions as a “marker” for our validation rule. If we’re doing schema first development we register the directive in the schema.</p> <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>type Order { ... customer: Customer @includeOnce } </code></pre></div></div> <p>While in code first it would be in the field definition</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">descriptor</span><span class="p">.</span><span class="nf">Field</span><span class="p">(</span><span class="s">"customer"</span><span class="p">)</span> <span class="p">.</span><span class="n">Directive</span><span class="p">&lt;</span><span class="n">IncludeOnceDirectiveType</span><span class="p">&gt;()</span> <span class="p">.</span><span class="n">Type</span><span class="p">&lt;</span><span class="n">NonNullType</span><span class="p">&lt;</span><span class="n">CustomerType</span><span class="p">&gt;&gt;()</span> <span class="p">...</span> </code></pre></div></div> <p>The directive also needs to be registered with the schema itself.</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">c</span><span class="p">.</span><span class="n">RegisterDirective</span><span class="p">&lt;</span><span class="n">IncludeOnceDirectiveType</span><span class="p">&gt;();</span> </code></pre></div></div> <h2 id="creating-the-validation-rule">Creating the validation rule</h2> <p>The implementation of the validation rule can be quite complex, the code below illustrates the concept but doesn’t cover some of the more complex cases (such as mutations). For a more fully featured example I suggest the <a href="https://github.com/ChilliCream/hotchocolate/blob/master/src/Core/Core/Validation/MaxComplexityRule.cs"><code class="highlighter-rouge">MaxComplexityRule</code></a> and <a href="https://github.com/ChilliCream/hotchocolate/blob/master/src/Core/Core/Validation/MaxComplexityVisitor.cs"><code class="highlighter-rouge">MaxComplexityVisitor</code></a> from the core repository.</p> <p>What we need to do is create a <code class="highlighter-rouge">QuerySyntaxWalker</code> that supports the traversal of the AST (abstract syntax tree), if you’ve done anything with Roslyn some of this will look familiar.</p> <p>It can look complicated, but we’re visiting each field within the query and maintaining some context from the parent fields we’ve visited. If we find a field whose definition has the <code class="highlighter-rouge">includeOnce</code> directive then we examine the list of parent fields, if any are a list type then we report an error.</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">IncludeOnceVisitor</span> <span class="p">:</span> <span class="n">QuerySyntaxWalker</span><span class="p">&lt;</span><span class="n">IncludeOnceContext</span><span class="p">&gt;</span> <span class="p">{</span> <span class="k">protected</span> <span class="k">override</span> <span class="kt">bool</span> <span class="n">VisitFragmentDefinitions</span> <span class="p">=&gt;</span> <span class="k">false</span><span class="p">;</span> <span class="k">protected</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">VisitField</span><span class="p">(</span><span class="n">FieldNode</span> <span class="n">node</span><span class="p">,</span> <span class="n">IncludeOnceContext</span> <span class="n">context</span><span class="p">)</span> <span class="p">{</span> <span class="kt">var</span> <span class="n">newContext</span> <span class="p">=</span> <span class="n">context</span><span class="p">;</span> <span class="k">if</span> <span class="p">(</span><span class="n">context</span><span class="p">.</span><span class="n">TypeContext</span> <span class="k">is</span> <span class="n">IComplexOutputType</span> <span class="n">type</span> <span class="p">&amp;&amp;</span> <span class="n">type</span><span class="p">.</span><span class="n">Fields</span><span class="p">.</span><span class="nf">TryGetField</span><span class="p">(</span><span class="n">node</span><span class="p">.</span><span class="n">Name</span><span class="p">.</span><span class="n">Value</span><span class="p">,</span> <span class="k">out</span> <span class="n">IOutputField</span> <span class="n">fieldDefinition</span><span class="p">))</span> <span class="p">{</span> <span class="n">newContext</span> <span class="p">=</span> <span class="n">newContext</span><span class="p">.</span><span class="nf">WithField</span><span class="p">(</span><span class="n">fieldDefinition</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">fieldDefinition</span><span class="p">.</span><span class="n">Type</span><span class="p">.</span><span class="nf">NamedType</span><span class="p">()</span> <span class="k">is</span> <span class="n">IComplexOutputType</span> <span class="n">ct</span><span class="p">)</span> <span class="p">{</span> <span class="n">newContext</span> <span class="p">=</span> <span class="n">newContext</span><span class="p">.</span><span class="nf">SetTypeContext</span><span class="p">(</span><span class="n">ct</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">fieldDefinition</span><span class="p">.</span><span class="n">Directives</span><span class="p">.</span><span class="nf">Contains</span><span class="p">(</span><span class="s">"includeOnce"</span><span class="p">))</span> <span class="p">{</span> <span class="kt">var</span> <span class="n">includedMoreThanOnce</span> <span class="p">=</span> <span class="n">context</span><span class="p">.</span><span class="n">FieldPath</span><span class="p">.</span><span class="nf">Any</span><span class="p">(</span><span class="n">f</span> <span class="p">=&gt;</span> <span class="n">f</span><span class="p">.</span><span class="n">Type</span><span class="p">.</span><span class="nf">IsListType</span><span class="p">());</span> <span class="k">if</span> <span class="p">(</span><span class="n">includedMoreThanOnce</span><span class="p">)</span> <span class="p">{</span> <span class="n">newContext</span><span class="p">.</span><span class="nf">ReportError</span><span class="p">(</span><span class="k">new</span> <span class="nf">ValidationError</span><span class="p">(</span><span class="s">$"The field </span><span class="p">{</span><span class="n">node</span><span class="p">.</span><span class="n">Name</span><span class="p">}</span><span class="s"> can only be includes once in a query"</span><span class="p">,</span> <span class="n">node</span><span class="p">));</span> <span class="p">}</span> <span class="p">}</span> <span class="p">}</span> <span class="k">base</span><span class="p">.</span><span class="nf">VisitField</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">newContext</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> <span class="p">}</span> <span class="k">public</span> <span class="k">class</span> <span class="nc">IncludeOnceContext</span> <span class="p">{</span> <span class="k">public</span> <span class="nf">IncludeOnceContext</span><span class="p">(</span><span class="n">ISchema</span> <span class="n">schema</span><span class="p">,</span> <span class="n">Action</span><span class="p">&lt;</span><span class="n">IError</span><span class="p">&gt;</span> <span class="n">reportError</span><span class="p">)</span> <span class="p">{</span> <span class="n">Schema</span> <span class="p">=</span> <span class="n">schema</span><span class="p">;</span> <span class="n">FieldPath</span> <span class="p">=</span> <span class="k">new</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">IOutputField</span><span class="p">&gt;();</span> <span class="n">ReportError</span> <span class="p">=</span> <span class="n">reportError</span><span class="p">;</span> <span class="p">}</span> <span class="k">protected</span> <span class="nf">IncludeOnceContext</span><span class="p">(</span><span class="n">ISchema</span> <span class="n">schema</span><span class="p">,</span> <span class="n">IEnumerable</span><span class="p">&lt;</span><span class="n">IOutputField</span><span class="p">&gt;</span> <span class="n">fieldPath</span><span class="p">,</span> <span class="n">Action</span><span class="p">&lt;</span><span class="n">IError</span><span class="p">&gt;</span> <span class="n">reportError</span><span class="p">)</span> <span class="p">{</span> <span class="n">Schema</span> <span class="p">=</span> <span class="n">schema</span><span class="p">;</span> <span class="n">FieldPath</span> <span class="p">=</span> <span class="n">fieldPath</span><span class="p">.</span><span class="nf">ToList</span><span class="p">();</span> <span class="n">ReportError</span> <span class="p">=</span> <span class="n">reportError</span><span class="p">;</span> <span class="p">}</span> <span class="k">public</span> <span class="n">Action</span><span class="p">&lt;</span><span class="n">IError</span><span class="p">&gt;</span> <span class="n">ReportError</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span> <span class="k">public</span> <span class="n">IList</span><span class="p">&lt;</span><span class="n">IOutputField</span><span class="p">&gt;</span> <span class="n">FieldPath</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span> <span class="k">public</span> <span class="n">ISchema</span> <span class="n">Schema</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span> <span class="k">public</span> <span class="n">INamedOutputType</span> <span class="n">TypeContext</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">protected</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> <span class="k">public</span> <span class="n">IncludeOnceContext</span> <span class="nf">WithField</span><span class="p">(</span><span class="n">IOutputField</span> <span class="n">field</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="k">new</span> <span class="nf">IncludeOnceContext</span><span class="p">(</span><span class="n">Schema</span><span class="p">,</span> <span class="n">FieldPath</span><span class="p">.</span><span class="nf">Concat</span><span class="p">(</span><span class="k">new</span><span class="p">[]</span> <span class="p">{</span> <span class="n">field</span> <span class="p">}),</span> <span class="n">ReportError</span><span class="p">);</span> <span class="p">}</span> <span class="k">public</span> <span class="n">IncludeOnceContext</span> <span class="nf">SetTypeContext</span><span class="p">(</span><span class="n">INamedOutputType</span> <span class="n">typeContext</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="k">new</span> <span class="nf">IncludeOnceContext</span><span class="p">(</span><span class="n">Schema</span><span class="p">,</span> <span class="n">FieldPath</span><span class="p">,</span> <span class="n">ReportError</span><span class="p">)</span> <span class="p">{</span> <span class="n">TypeContext</span> <span class="p">=</span> <span class="n">typeContext</span> <span class="p">};</span> <span class="p">}</span> <span class="p">}</span> </code></pre></div></div> <p>After all this, the validation rule itself is pretty straightforward. Create a visitor, explore the document, then report if there are any errors.</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">IncludeOnceValidationRule</span> <span class="p">:</span> <span class="n">IQueryValidationRule</span> <span class="p">{</span> <span class="k">private</span> <span class="k">static</span> <span class="k">readonly</span> <span class="n">IncludeOnceVisitor</span> <span class="n">includeOnceVisitor</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">IncludeOnceVisitor</span><span class="p">();</span> <span class="k">public</span> <span class="n">QueryValidationResult</span> <span class="nf">Validate</span><span class="p">(</span><span class="n">ISchema</span> <span class="n">schema</span><span class="p">,</span> <span class="n">DocumentNode</span> <span class="n">queryDocument</span><span class="p">)</span> <span class="p">{</span> <span class="kt">var</span> <span class="n">errors</span> <span class="p">=</span> <span class="k">new</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">IError</span><span class="p">&gt;();</span> <span class="kt">var</span> <span class="n">context</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">IncludeOnceContext</span><span class="p">(</span><span class="n">schema</span><span class="p">,</span> <span class="n">errors</span><span class="p">.</span><span class="n">Add</span><span class="p">).</span><span class="nf">SetTypeContext</span><span class="p">(</span><span class="n">schema</span><span class="p">.</span><span class="n">QueryType</span><span class="p">);</span> <span class="n">includeOnceVisitor</span><span class="p">.</span><span class="nf">Visit</span><span class="p">(</span><span class="n">queryDocument</span><span class="p">,</span> <span class="n">context</span><span class="p">);</span> <span class="k">return</span> <span class="n">errors</span><span class="p">.</span><span class="nf">Any</span><span class="p">()</span> <span class="p">?</span> <span class="k">new</span> <span class="nf">QueryValidationResult</span><span class="p">(</span><span class="n">errors</span><span class="p">)</span> <span class="p">:</span> <span class="n">QueryValidationResult</span><span class="p">.</span><span class="n">OK</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span> </code></pre></div></div> <p>The one final step is register our new validation rule with the schema</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">.</span><span class="nf">AddExecutionConfiguration</span><span class="p">(</span><span class="n">execution</span> <span class="p">=&gt;</span> <span class="n">execution</span> <span class="p">.</span><span class="n">AddValidationRule</span><span class="p">&lt;</span><span class="n">IncludeOnceValidationRule</span><span class="p">&gt;()</span> <span class="p">)</span> </code></pre></div></div> <p>We can now validate that our poorly performing field is only included in queries that will not exacerbate the issue. Hope this helps.</p> Wed, 13 Mar 2019 00:00:00 +0000 http://compiledexperience.com/blog/posts/graphql-n+1 http://compiledexperience.com/blog/posts/graphql-n+1 nigel.sampson@compiledexperience.com (Nigel Sampson) csharp graphql Exporting a GraphQL Schema <p>I’ve been playing around with <a href="https://graphql.org/">GraphQL</a> at work quite a bit lately and starting to put together some thoughts on how it can fit into your application (and more importantly where it doesn’t).</p> <p>One of the things we found we needed everyonce in a while was an export of the schema in the <code class="highlighter-rouge">.graphql</code> format. Most of the time we were definining our schema in a “code first* way using <a href="https://graphql-dotnet.github.io/">GraphQL.NET</a>, so we typically didn’t have this file to work from.</p> <p>However a number of tools / frameworks work well if they can import one of these schemas, a good example is schema stiching using <a href="https://hotchocolate.io/">Hot Chocolate</a>.</p> <p>So how do we export a schema from an already existing <a href="https://graphql-dotnet.github.io/">GraphQL.NET</a> service?</p> <p>Thankfully support comes in terms of the <code class="highlighter-rouge">SchemaPrinter</code> class. This takes an instance of your <code class="highlighter-rouge">Schema</code> that you’ve created by any of the mechanisms the framework supports.</p> <p>Usage looks something like</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">printer</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SchemaPrinter</span><span class="p">(</span><span class="n">_schema</span><span class="p">,</span> <span class="k">new</span> <span class="n">SchemaPrinterOptions</span> <span class="p">{</span> <span class="n">IncludeDeprecationReasons</span> <span class="p">=</span> <span class="k">true</span><span class="p">,</span> <span class="n">IncludeDescriptions</span> <span class="p">=</span> <span class="k">true</span> <span class="p">}))</span> <span class="p">{</span> <span class="n">context</span><span class="p">.</span><span class="n">Response</span><span class="p">.</span><span class="n">ContentType</span> <span class="p">=</span> <span class="s">"application/text"</span><span class="p">;</span> <span class="n">context</span><span class="p">.</span><span class="n">Response</span><span class="p">.</span><span class="n">StatusCode</span> <span class="p">=</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="n">HttpStatusCode</span><span class="p">.</span><span class="n">OK</span><span class="p">;</span> <span class="k">await</span> <span class="n">context</span><span class="p">.</span><span class="n">Response</span><span class="p">.</span><span class="nf">WriteAsync</span><span class="p">(</span><span class="n">printer</span><span class="p">.</span><span class="nf">Print</span><span class="p">());</span> <span class="k">return</span><span class="p">;</span> <span class="p">}</span> </code></pre></div></div> <p>I’m using the code in my GraphQL middleware where if no query was posted then we return the schema.</p> <p>Hope this helps someone.</p> Tue, 26 Feb 2019 00:00:00 +0000 http://compiledexperience.com/blog/posts/exporting-graphql-schema http://compiledexperience.com/blog/posts/exporting-graphql-schema nigel.sampson@compiledexperience.com (Nigel Sampson) csharp graphql EF Core Client Side evaluation (and how to stop it) <p>EF Core has a feature that supports parts of a query being evaluated on the server and parts on the client, the decision is driven by the whether the underlying LINQ provider can convert the expression into SQL.</p> <p>An example would be if we had a method like the following:</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">static</span> <span class="kt">decimal</span> <span class="nf">CalculateTax</span><span class="p">(</span><span class="kt">decimal</span> <span class="n">price</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="n">price</span> <span class="p">*</span> <span class="m">0.15</span><span class="n">m</span><span class="p">;</span> </code></pre></div></div> <p>and we used it in the query that looked like</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">products</span> <span class="p">=</span> <span class="n">context</span><span class="p">.</span><span class="n">Products</span> <span class="p">.</span><span class="nf">OrderBy</span><span class="p">(</span><span class="n">p</span> <span class="p">=&gt;</span> <span class="n">p</span><span class="p">.</span><span class="n">Price</span><span class="p">)</span> <span class="p">.</span><span class="nf">Select</span><span class="p">(</span><span class="n">p</span> <span class="p">=&gt;</span> <span class="k">new</span> <span class="p">{</span> <span class="n">p</span><span class="p">.</span><span class="n">Id</span><span class="p">,</span> <span class="n">p</span><span class="p">.</span><span class="n">Price</span><span class="p">,</span> <span class="n">Tax</span> <span class="p">=</span> <span class="nf">CalculateTax</span><span class="p">(</span><span class="n">p</span><span class="p">.</span><span class="n">Price</span><span class="p">)</span> <span class="p">});</span> </code></pre></div></div> <p>the LINQ provider knows how to convert the <code class="highlighter-rouge">OrderBy</code> clause to SQL so that will be run on the server, but it has no idea how to convert the <code class="highlighter-rouge">CalculateTax</code> method to SQL so the <code class="highlighter-rouge">Select</code> clause will be run on the client. From the point of view of the developer unless you’re looking very carefully at your query it’s not immediately apparent what will run where.</p> <p>Consider the following query:</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">products</span> <span class="p">=</span> <span class="n">context</span><span class="p">.</span><span class="n">Products</span> <span class="p">.</span><span class="nf">Where</span><span class="p">(</span><span class="n">p</span> <span class="p">=&gt;</span> <span class="nf">CalculateTax</span><span class="p">(</span><span class="n">p</span><span class="p">.</span><span class="n">Price</span><span class="p">)</span> <span class="p">&gt;</span> <span class="m">100.0</span><span class="n">m</span><span class="p">);</span> </code></pre></div></div> <p>Again we can’t evaulate <code class="highlighter-rouge">CalculateTax</code> server side so it’s evalated client side. For this to happen we’ve had to pull the entire contents of the Products table into memory! If this table is of a significant size then the performance problems in terms of memory and time are going to be really nasty.</p> <p>Now both of the above queries are pretty simple, it’s relatively easy to determine what the client / server execution breakdown will look like, however as queries become more complex this task becomes harder and you run the risk of introducing nasty performence regressions.</p> <p>EF Core will log when it drops from server to client evaluation it will log this occurance, but it can be easy to miss.</p> <p>To sum this feature up, I’d avoid it like the plague. Client side evaluation makes it too easy to write a query that has unintended performance regressions without noticing until it’s till late.</p> <p>In my opinion it’s better to be explicit on defining where the query happens. But the best first step is disabling client side evaluation, the following code on the <code class="highlighter-rouge">DbContext</code> changes the drop from server to client from a log warning to an exception.</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">protected</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">OnConfiguring</span><span class="p">(</span><span class="n">DbContextOptionsBuilder</span> <span class="n">optionsBuilder</span><span class="p">)</span> <span class="p">{</span> <span class="n">optionsBuilder</span> <span class="p">.</span><span class="nf">ConfigureWarnings</span><span class="p">(</span><span class="n">w</span> <span class="p">=&gt;</span> <span class="n">w</span><span class="p">.</span><span class="nf">Throw</span><span class="p">(</span><span class="n">RelationalEventId</span><span class="p">.</span><span class="n">QueryClientEvaluationWarning</span><span class="p">));</span> <span class="p">}</span> </code></pre></div></div> <p>This means that whenever you write a query that can’t fully be evaluated in SQL an exception will be thrown and we’ll be fully aware of our problem (at development time).</p> <p>Revisiting our earlier query that would now throw an exception would need to be written to something like in order to not throw that exception.</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">products</span> <span class="p">=</span> <span class="n">context</span><span class="p">.</span><span class="n">Products</span><span class="p">.</span><span class="nf">ToList</span><span class="p">();</span> <span class="n">products</span> <span class="p">=</span> <span class="n">products</span><span class="p">.</span><span class="nf">Where</span><span class="p">(</span><span class="n">p</span> <span class="p">=&gt;</span> <span class="nf">CalculateTax</span><span class="p">(</span><span class="n">p</span><span class="p">.</span><span class="n">Price</span><span class="p">)</span> <span class="p">&gt;</span> <span class="m">100.0</span><span class="n">m</span><span class="p">).</span><span class="nf">ToList</span><span class="p">();</span> </code></pre></div></div> <p>It’s now very clear what is being evaulated server side and what’s on the client side and hopefully the code smell of the entire Products table being loaded into memory is very apparent.</p> <p>In short, disable this feature as the first thing you do in order to not shoot yourself in the foot.</p> <p>Hope this helps.</p> Wed, 30 Jan 2019 00:00:00 +0000 http://compiledexperience.com/blog/posts/ef-core-client-side-eval http://compiledexperience.com/blog/posts/ef-core-client-side-eval nigel.sampson@compiledexperience.com (Nigel Sampson) csharp ef Moving EF Core migrations to their own assembly <p>If you follow an introduction to EF Core tutorial then you’ll tend to find the migrations end up in the same assembly as the models and DB context. For a lot of people this is fine but personally I prefer to move them off to their own assembly. For me this is about seperating a run time concern (the model and the context) from a deployment concern (the migrations), but this is completely subjective.</p> <p>So if you’ve been following the tutorials and have all these concerns in the same assembly what does it take to seperate them? Thankfully not too much.</p> <p>For the sake of this example we’ll assume I have a project <code class="highlighter-rouge">MyMicroService.Core</code> which has a <code class="highlighter-rouge">Migrations</code> folder along side our application code as well as <code class="highlighter-rouge">MyMicroService.API</code> that is the ASP.NET Core project that makes use of the EF Core models.</p> <ol> <li>Create the project <code class="highlighter-rouge">MyMicroService.Core.Migrations</code> to hold the migrations. I deliberately named this to match it up with the existing namespace of the migrations.</li> <li>Add refereces to EF Core and related packages to the migrations project, in my case this included <code class="highlighter-rouge">Npgsql.EntityFrameworkCore.PostgreSQL</code>.</li> <li>Add a reference from <code class="highlighter-rouge">MyMicroService.Core.Migrations</code> to <code class="highlighter-rouge">MyMicroService.Core</code>. The generated migrations reference the <code class="highlighter-rouge">DbContext</code> in code like the following, so the migrations project needs to reference the core project. <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">[DbContext(typeof(MyMicroServiceDbContext))]</span> </code></pre></div> </div> </li> <li>Copy the migrations and model snapshot files to the new project. Given the naming we did in step 1 this should just be a copy / paste of the folder in question.</li> <li>Configure the <code class="highlighter-rouge">DbContext</code> with the new assebmly <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">options</span><span class="p">.</span><span class="nf">UseNpgsql</span><span class="p">(</span><span class="n">connectionString</span><span class="p">,</span> <span class="n">o</span> <span class="p">=&gt;</span> <span class="n">o</span><span class="p">.</span><span class="nf">MigrationsAssembly</span><span class="p">(</span><span class="s">"MyMicroService.Core.Migrations"</span><span class="p">));</span> </code></pre></div> </div> </li> <li>Add a reference from the startup assembly <code class="highlighter-rouge">MyMicroService.API</code> to the migrations assembly. This is lets us do things such as check if our database is up to date etc.</li> </ol> <p>And we’re done, hope this helps.</p> Wed, 23 Jan 2019 00:00:00 +0000 http://compiledexperience.com/blog/posts/ef-core-migrations http://compiledexperience.com/blog/posts/ef-core-migrations nigel.sampson@compiledexperience.com (Nigel Sampson) csharp ef Interesting uses of tuple deconstruction <p>C# 7.0 brought us a new and interesting feature with tuple types and tuple literals. These coupled with tuple deconstruction let us create new syntax patterns and helper methods that hopefully results in more readable code.</p> <p>One bug bear of mine was the way we ended up having to use <code class="highlighter-rouge">Task.WhenAll</code> when wanting to await mutiple tasks at the same time. If you didn’t need the results of the <code class="highlighter-rouge">Task</code>’s then it wasn’t too bad.</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">await</span> <span class="n">Task</span><span class="p">.</span><span class="nf">WhenAll</span><span class="p">(</span><span class="nf">StartTaskOne</span><span class="p">(),</span> <span class="nf">StartTaskTwo</span><span class="p">());</span> </code></pre></div></div> <p>but when we want the results of the tasks when end up with syntax that looks like</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">count</span> <span class="p">=</span> <span class="nf">GetCount</span><span class="p">();</span> <span class="kt">var</span> <span class="n">description</span> <span class="p">=</span> <span class="nf">GetDescription</span><span class="p">();</span> <span class="k">await</span> <span class="n">Task</span><span class="p">.</span><span class="nf">WhenAll</span><span class="p">(</span><span class="n">count</span><span class="p">,</span> <span class="n">description</span><span class="p">);</span> <span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="s">$"Count: </span><span class="p">{</span><span class="n">count</span><span class="p">.</span><span class="n">Result</span><span class="p">}</span><span class="s">, Description: </span><span class="p">{</span><span class="n">description</span><span class="p">.</span><span class="n">Result</span><span class="p">}</span><span class="s">"</span><span class="p">);</span> </code></pre></div></div> <p>What we can do is create an extension method that extends a <code class="highlighter-rouge">ValueTuple</code> of <code class="highlighter-rouge">Tasks</code>’s awaits them and results another tuple of the results.</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">static</span> <span class="k">class</span> <span class="nc">TaskExtensions</span> <span class="p">{</span> <span class="k">public</span> <span class="k">static</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">ValueTuple</span><span class="p">&lt;</span><span class="n">T1</span><span class="p">,</span> <span class="n">T2</span><span class="p">&gt;&gt;</span> <span class="n">WhenAll</span><span class="p">&lt;</span><span class="n">T1</span><span class="p">,</span> <span class="n">T2</span><span class="p">&gt;(</span><span class="k">this</span> <span class="n">ValueTuple</span><span class="p">&lt;</span><span class="n">Task</span><span class="p">&lt;</span><span class="n">T1</span><span class="p">&gt;,</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">T2</span><span class="p">&gt;&gt;</span> <span class="n">tasks</span><span class="p">)</span> <span class="p">{</span> <span class="k">await</span> <span class="n">Task</span><span class="p">.</span><span class="nf">WhenAll</span><span class="p">(</span><span class="n">tasks</span><span class="p">.</span><span class="n">Item1</span><span class="p">,</span> <span class="n">tasks</span><span class="p">.</span><span class="n">Item2</span><span class="p">);</span> <span class="k">return</span> <span class="p">(</span><span class="n">tasks</span><span class="p">.</span><span class="n">Item1</span><span class="p">.</span><span class="n">Result</span><span class="p">,</span> <span class="n">tasks</span><span class="p">.</span><span class="n">Item2</span><span class="p">.</span><span class="n">Result</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> </code></pre></div></div> <p>When then end up with more readable</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="p">(</span><span class="n">count</span><span class="p">,</span> <span class="n">description</span><span class="p">)</span> <span class="p">=</span> <span class="k">await</span> <span class="p">(</span><span class="nf">GetCount</span><span class="p">(),</span> <span class="nf">GetDescription</span><span class="p">()).</span><span class="nf">WhenAll</span><span class="p">();</span> <span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="s">$"Count: </span><span class="p">{</span><span class="n">count</span><span class="p">}</span><span class="s">, Description: </span><span class="p">{</span><span class="n">description</span><span class="p">}</span><span class="s">"</span><span class="p">);</span> </code></pre></div></div> <p>Sadly the above extension method only works with two tasks, but you can see how you’d write a three task version. As the C# language stands right now there’s no way to build a generic version that would work with any amount of tasks (though I’d be very happy to be proven wrong here). I’d argue though if you need overloads of this method beyond four or five something has gone awfully wrong in your code base.</p> Tue, 18 Dec 2018 00:00:00 +0000 http://compiledexperience.com/blog/posts/abusing-tuples http://compiledexperience.com/blog/posts/abusing-tuples nigel.sampson@compiledexperience.com (Nigel Sampson) csharp Project references to multi-targeted projects <p>During the process of moving Caliburn.Micro to .NET Standard and the new <a href="https://caliburnmicro.com/announcements/net-standard">multi-targeting project format</a> I’ve encountered a number of issues in the tooling around intellisense and builds. This isn’t surprising given the relative newness of this approach, but I thought I’d share some of the issues over the next few weeks to help you out.</p> <p>One of the first things I did was move <code class="highlighter-rouge">Caliburn.Micro.Platform</code> from a number of projects (around five I believe) in the same folder (one for each platform) to the new “SDK style” project format which allows multiple outputs based on a series of target frameworks (rather than the normal singular framework).</p> <p>This worked out fine, but the unit tests in the solution started failing with compilation errors where certain classes were missing. In this case it was classes that aren’t present in the Xamarin.Forms platform. This unit test project was a .NET 4.5 project and was clearly picking the wrong output of the multi-targeted project. Instead of picking the “best” platform of .NET 4.5, it was picking the widest in .NET Standard 1.4.</p> <p>This is a known issue and you can see it being discussed on the GitHub repository for the new project system under <a href="https://github.com/dotnet/project-system/issues/1162">“P2P refs choose first tfm in multi-targting reference, not closest one in legacy project system”</a>.</p> <p>If you’ve read the above issue you’ll notice the way to solve this is to shift the other project to the new poject system. Once this is done the new project will pick the correct project output.</p> <p>As I run into more problems during this port (hopefully not too many) I’ll post them up here.</p> Tue, 14 Nov 2017 00:00:00 +0000 http://compiledexperience.com/blog/posts/project-references-multi-targeting http://compiledexperience.com/blog/posts/project-references-multi-targeting nigel.sampson@compiledexperience.com (Nigel Sampson) csharp xamarin Techniques in creating great cross platform apps <p>My NDC Sydney 2017 talk “<a href="https://www.youtube.com/watch?v=S9kxokKuFAQ">Techniques in creating great cross platform apps</a>” is now available on Youtube.</p> <p>This talk covers a number of topics:</p> <ul> <li>A quick recap of Xamarin and the MVVM pattern.</li> <li>New approaches to share code with Visual Studio 2017.</li> <li>Composition of view models using view locators.</li> <li>Multiple views per view model to create master / details.</li> <li>View model lifecycle and conductors.</li> <li>Messanging and event aggregation.</li> </ul> <p>If you have any feedback and / or questions feel free to get in contact.</p> Fri, 29 Sep 2017 00:00:00 +0000 http://compiledexperience.com/blog/posts/ndc-sydney-2017-video http://compiledexperience.com/blog/posts/ndc-sydney-2017-video nigel.sampson@compiledexperience.com (Nigel Sampson) csharp xamarin caliburn-micro Auto subscription for Event Aggregator <p>In many of my talks I’ve recommended using a messenger style class. These help to reduce coupling between view models when decomposing from a single “view model per screen” to a tree of view models. This intermediary class is called by a few different names, <code class="highlighter-rouge">Messenger</code> in Xamarin.Forms, <code class="highlighter-rouge">Mediator</code> in some others and in Caliburn.Micro, <code class="highlighter-rouge">Event Aggregator</code>.</p> <p>One feature of the <code class="highlighter-rouge">Event Aggregator</code> in Caliburn.Micro is that you need to explicitly subscribe to it through <code class="highlighter-rouge">IEventAggregator.Subscribe</code> before you’ll receive events from it. This is by design to be able to integrate the aggreator with the life cycle of your view models. Typically most view models will only want to receive events while they’ve active, some however want to receive them all the time.</p> <p>Some developers would prefer an “auto subscription” style behavior where view models are automatically subscribed to the aggregator when they’re used. One benefit of this approach is that the view model doesn’t need to take a dependency on aggregator itself reducing some complexity.</p> <p>The best cut point to introduce this behavior in Caliburn.Micro is the <code class="highlighter-rouge">ViewModelBinder.Bind</code>, this is the part of the framework that once a view and view model are located they’re “bound” together. This <code class="highlighter-rouge">ViewModelBinder</code> is used by the <code class="highlighter-rouge">INavigationService</code> and the <code class="highlighter-rouge">View.Model</code> attached property and covers a few things:</p> <ol> <li>Sets the <code class="highlighter-rouge">DataContext / BindingContext</code> of the view to the view model.</li> <li>Applies the property conventions (not for Xamarin.Forms).</li> <li>Applies the method conventions (not for Xamarin.Forms).</li> </ol> <p>A lot of the extension points in Caliburn.Micro like this one are defined as static properties, in this case of type <code class="highlighter-rouge">Action&lt;object, DependencyObject, object&gt;</code>. The way we modify it is by setting it to a new action that includes the new behavior, we can preserve the existing functionality by taking a reference to the current action and calling it within the new action. This looks like the following:</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">existingBind</span> <span class="p">=</span> <span class="n">ViewModelBinder</span><span class="p">.</span><span class="n">Bind</span><span class="p">;</span> <span class="n">ViewModelBinder</span><span class="p">.</span><span class="n">Bind</span> <span class="p">=</span> <span class="p">(</span><span class="n">viewModel</span><span class="p">,</span> <span class="n">view</span><span class="p">,</span> <span class="n">context</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span> <span class="nf">existingBind</span><span class="p">(</span><span class="n">viewModel</span><span class="p">,</span> <span class="n">view</span><span class="p">,</span> <span class="n">context</span><span class="p">);</span> <span class="kt">var</span> <span class="n">handleInterfaces</span> <span class="p">=</span> <span class="k">new</span><span class="p">[]</span> <span class="p">{</span> <span class="k">typeof</span><span class="p">(</span><span class="n">IHandle</span><span class="p">&lt;&gt;),</span> <span class="k">typeof</span><span class="p">(</span><span class="n">IHandleWithCoroutine</span><span class="p">&lt;&gt;),</span> <span class="k">typeof</span><span class="p">(</span><span class="n">IHandleWithTask</span><span class="p">&lt;&gt;)</span> <span class="p">};</span> <span class="kt">var</span> <span class="n">subscribe</span> <span class="p">=</span> <span class="n">viewModel</span> <span class="p">.</span><span class="nf">GetType</span><span class="p">()</span> <span class="p">.</span><span class="nf">GetInterfaces</span><span class="p">()</span> <span class="p">.</span><span class="nf">Any</span><span class="p">(</span><span class="n">i</span> <span class="p">=&gt;</span> <span class="n">i</span><span class="p">.</span><span class="n">IsGenericType</span> <span class="p">&amp;&amp;</span> <span class="n">handleInterfaces</span><span class="p">.</span><span class="nf">Contains</span><span class="p">(</span><span class="n">i</span><span class="p">.</span><span class="nf">GetGenericTypeDefinition</span><span class="p">()));</span> <span class="k">if</span> <span class="p">(!</span><span class="n">subscribe</span><span class="p">)</span> <span class="k">return</span><span class="p">;</span> <span class="kt">var</span> <span class="n">eventAggregator</span> <span class="p">=</span> <span class="n">container</span><span class="p">.</span><span class="n">GetInstance</span><span class="p">&lt;</span><span class="n">IEventAggregator</span><span class="p">&gt;();</span> <span class="n">eventAggregator</span><span class="p">.</span><span class="nf">Subscribe</span><span class="p">(</span><span class="n">viewModel</span><span class="p">);</span> <span class="kt">var</span> <span class="n">deactivate</span> <span class="p">=</span> <span class="n">viewModel</span> <span class="k">as</span> <span class="n">IDeactivate</span><span class="p">;</span> <span class="k">if</span> <span class="p">(</span><span class="n">deactivate</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span> <span class="p">{</span> <span class="n">deactivate</span><span class="p">.</span><span class="n">Deactivated</span> <span class="p">+=</span> <span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">e</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span> <span class="k">if</span> <span class="p">(</span><span class="n">e</span><span class="p">.</span><span class="n">WasClosed</span><span class="p">)</span> <span class="n">eventAggregator</span><span class="p">.</span><span class="nf">Unsubscribe</span><span class="p">(</span><span class="k">this</span><span class="p">);</span> <span class="p">};</span> <span class="p">}</span> <span class="p">};</span> </code></pre></div></div> <p>In the above code we’re checking whether the view model implements one of <code class="highlighter-rouge">IHandle*</code> interfaces that’s required by the event aggregator, if it doesn’t we can exit out otherwise we’ll subscribe the view model to the event aggregator. We’ll then check if the view model supports deactivation, if it does we’ll attach to the <code class="highlighter-rouge">Deactivated</code> event and if we’re closing the view model we’ll unsubscribe.</p> <p>Unsubscribing is important because although the event aggregator itself holds a weak reference to your view model, you have the possibility of discarded but not yet garbage collected view models receiving events and acting erroneously.</p> <p>This post should show how we can extend Caliburn.Micro to add automatic behavior to view models without too much extra complexity.</p> Mon, 11 Sep 2017 00:00:00 +0000 http://compiledexperience.com/blog/posts/event-aggregator-autosubscribe http://compiledexperience.com/blog/posts/event-aggregator-autosubscribe nigel.sampson@compiledexperience.com (Nigel Sampson) csharp xamarin caliburn-micro Command conventions in Caliburn.Micro <p>If you’ve ever spoken to me personally at a convention or a user group (I’ll be at <a href="http://ndcsydney.com/">NDC Sydney</a> if next week, comes say hello) then you may have heard me talk about disliking command objects in MVVM.</p> <p>In my opinion (and it’s just that, my opinion) most commands don’t add any value to the main goals for using MVVM (maintainability, readability and testability). Typically they’re just an object that wraps a method, sometimes also a predicate for CanExecute but that’s it. What they mostly add is ceremony to the view model and not much more, you typically see this in commands named <code class="highlighter-rouge">RelayCommand</code> or <code class="highlighter-rouge">DelegateCommand</code>.</p> <p>Some commands are really useful however, <code class="highlighter-rouge">ReactiveCommand</code> in <a href="https://reactiveui.net/">ReactiveUI</a> adds a lot of value when building that style of application and I highly recommend them. This is a great example where the command adds more then just the ceremony of passing execution to the method.</p> <p>How can we customize the conventions in Caliburn.Micro to make use of commands? Given that we’d be binding to the command property on the control we can simply modify the convention for controls such as Button.</p> <p>This change to the convention is set up during app initialisation. The important parameter is the first, this defines that when we find a property on the view model matching the <code class="highlighter-rouge">x:Name</code> of the button then this is the dependency property we’ll bind that property to.</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">ConventionManager</span><span class="p">.</span><span class="n">AddElementConvention</span><span class="p">&lt;</span><span class="n">Button</span><span class="p">&gt;(</span><span class="n">ButtonBase</span><span class="p">.</span><span class="n">CommandProperty</span><span class="p">,</span> <span class="s">"CommandParameter"</span><span class="p">,</span> <span class="s">"Click"</span><span class="p">);</span> </code></pre></div></div> <p>To keep our view model sample simple I’ll use a <code class="highlighter-rouge">DelegateCommand</code></p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="nf">LoginViewModel</span><span class="p">()</span> <span class="p">{</span> <span class="n">Login</span> <span class="p">=</span> <span class="k">new</span> <span class="n">DelegateCommand</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">&gt;(</span><span class="n">LoginImpl</span><span class="p">,</span> <span class="n">CanLogin</span><span class="p">);</span> <span class="p">}</span> <span class="k">public</span> <span class="n">ICommand</span> <span class="n">Login</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span> <span class="k">private</span> <span class="kt">bool</span> <span class="nf">CanLogin</span><span class="p">(</span><span class="kt">string</span> <span class="n">token</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">!</span><span class="n">String</span><span class="p">.</span><span class="nf">IsNullOrWhiteSpace</span><span class="p">(</span><span class="n">token</span><span class="p">);</span> <span class="k">private</span> <span class="k">void</span> <span class="nf">LoginImpl</span><span class="p">(</span><span class="kt">string</span> <span class="n">token</span><span class="p">)</span> <span class="p">{</span> <span class="p">....</span> <span class="p">}</span> </code></pre></div></div> <p>Now with our convention in place we can simply give the <code class="highlighter-rouge">Button</code> the <code class="highlighter-rouge">x:Name</code> we normally would but instead of a method being called the command will be executed.</p> <div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;StackPanel&gt;</span> <span class="nt">&lt;TextBox</span> <span class="na">x:Name=</span><span class="s">"Token"</span> <span class="nt">/&gt;</span> <span class="nt">&lt;Button</span> <span class="na">x:Name=</span><span class="s">"Login"</span> <span class="na">Content=</span><span class="s">"Login to System"</span> <span class="na">CommandParameter=</span><span class="s">"{Binding ElementName=Token, Path=Text}"</span> <span class="nt">/&gt;</span> <span class="nt">&lt;/StackPanel&gt;</span> </code></pre></div></div> <p>If you’re looking to combine the best of <a href="http://caliburnmicro.com/">Caliburn.Micro</a> and <a href="https://reactiveui.net/">ReactiveUI</a> then this may help.</p> Thu, 10 Aug 2017 00:00:00 +0000 http://compiledexperience.com/blog/posts/comand-conventions http://compiledexperience.com/blog/posts/comand-conventions nigel.sampson@compiledexperience.com (Nigel Sampson) csharp xamarin caliburn-micro Controlling the output path in Visual Studio 2017 <p>One thing you’ll notice if you’re experimenting with the new <code class="highlighter-rouge">csproj</code> project structure used in .NET Standard is the difference in <strong>Output Path</strong>. Typically the default output path for a new full .NET Framework assembly would be <code class="highlighter-rouge">bin\$(Configuration)\</code> resulting in <code class="highlighter-rouge">bin\Debug\</code> and <code class="highlighter-rouge">\bin\Release\</code>. In .NET Standard projects by default this output path isn’t defined in the <code class="highlighter-rouge">csproj</code> but defaults to much the same <strong>except</strong> that the Target Framework is also appended to the path. So for example if I created a new project targeting .NET Standard 1.4 like follows:</p> <div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;Project</span> <span class="na">Sdk=</span><span class="s">"Microsoft.NET.Sdk"</span><span class="nt">&gt;</span> <span class="nt">&lt;PropertyGroup&gt;</span> <span class="nt">&lt;TargetFramework&gt;</span>netstandard1.4<span class="nt">&lt;/TargetFramework&gt;</span> <span class="nt">&lt;/PropertyGroup&gt;</span> <span class="nt">&lt;/Project&gt;</span> </code></pre></div></div> <p>then the default output path would be <code class="highlighter-rouge">bin\Debug\netstandard1.4</code>. Nothing too different but something to watch out for. This makes sense for when instead of having one Target Framework we convert the project to target multiple frameworks, by default then each framework would have it’s own output folder and we wouldn’t have any file clashes.</p> <p>What’s also very important to note is that this appending on of the Target Framework happens automatically even when the output path is defined by you. For instance the output path of the following would be <code class="highlighter-rouge">build\Debug\netstandard1.4</code>.</p> <div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;Project</span> <span class="na">Sdk=</span><span class="s">"Microsoft.NET.Sdk"</span><span class="nt">&gt;</span> <span class="nt">&lt;PropertyGroup&gt;</span> <span class="nt">&lt;TargetFramework&gt;</span>netstandard1.4<span class="nt">&lt;/TargetFramework&gt;</span> <span class="nt">&lt;OutputPath&gt;</span>build\$(Configuration)<span class="nt">&lt;/OutputPath&gt;</span> <span class="nt">&lt;/PropertyGroup&gt;</span> <span class="nt">&lt;/Project&gt;</span> </code></pre></div></div> <p>If you want to disable this automatic appending, for instance you’re only going to be using one target framework or you’re defining a different output path per framework then you can use <code class="highlighter-rouge">AppendTargetFrameworkToOutputPath</code>.</p> <div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;Project</span> <span class="na">Sdk=</span><span class="s">"Microsoft.NET.Sdk"</span><span class="nt">&gt;</span> <span class="nt">&lt;PropertyGroup&gt;</span> <span class="nt">&lt;TargetFramework&gt;</span>netstandard1.4<span class="nt">&lt;/TargetFramework&gt;</span> <span class="nt">&lt;AppendTargetFrameworkToOutputPath&gt;</span>false<span class="nt">&lt;/AppendTargetFrameworkToOutputPath&gt;</span> <span class="nt">&lt;/PropertyGroup&gt;</span> <span class="nt">&lt;/Project&gt;</span> </code></pre></div></div> Wed, 26 Jul 2017 00:00:00 +0000 http://compiledexperience.com/blog/posts/multi-targeting-output-path http://compiledexperience.com/blog/posts/multi-targeting-output-path nigel.sampson@compiledexperience.com (Nigel Sampson) csharp xamarin