https://www.nyami.uk/
Copyright © 2022
2022-03-31T09:35:27Z
Something interesting for sure...
https://www.nyami.uk/posts/2022/2022-03-31-verifying-calls-with-nsubstitute
Verifying calls with NSubstitute
2022-03-31T00:00:00Z
<p>This one came up recently so I thought I would do a post for my future self, so I have something to come back to. Being a conscientious developer <a id="fnref:1" href="https://www.nyami.uk/#fn:1" class="footnote-ref"><sup>1</sup></a> I was creating unit tests and I found a situation where I wanted to verify the call to a method was the expected call, in this case the functionality being tested was creating an object and then calling a repository to persist this, I needed to check the object being persisted was as I expected.</p>
<!--more-->
<p>Here is a rather simplified example of what we want to test:</p>
<pre><code class="language-CSharp">class MyThing {
readonly IFoo foo;
public MyThing(IFoo foo) {
this.foo = foo;
}
public async Task<bool> DoTheThing(int howManyTimes) {
var x = new List<int>();
for (int i = 1; i <= howManyTimes; i++) {
x.Add(i);
}
foo.DoSomething(x);
return await Task.FromResult(true);
}
}
public interface IFoo {
void DoSomething(IList<int> list);
}
</code></pre>
<p>Using NSubstitute we can create a mock for IFoo using <code>NSubstitute.Substitute.For<IFoo>()</code>, and now this can be used to verify calls using <code>Received()</code>:</p>
<pre><code class="language-CSharp">// Arrange
var foo = NSubstitute.Substitute.For<IFoo>();
// Act
var sut = new MyThing(foo);
await sut.DoTheThing(3);
// Assert
foo.Received().DoSomething(Arg.Is<IList<int>>(l => l.Count() == 3));
foo.Received().DoSomething(Arg.Is<IList<int>>(l => l.First() == 1));
foo.Received().DoSomething(Arg.Is<IList<int>>(l => l.Last() == 3));
</code></pre>
<p>We could alternatively pass in a function that could do some more complex checks, eg:</p>
<pre><code class="language-CSharp">Func<IList<int>, bool> expectedResult = (list) => { return false;};
foo.Received().DoSomething(Arg.Is<IList<int>>(l => expectedResult(l)));
</code></pre>
<p>or we could even capture the arguments used using <code>Do</code> by setting this up during our arrangement:</p>
<pre><code class="language-CSharp">IList<int> captured = null!;
foo.When(substitute => substitute.DoSomething(Arg.Any<IList<int>>())).Do(info => captured = info.ArgAt<IList<int>>(0));
</code></pre>
<p>NSubstitute can do a whole lot more and you could really go to town with some of the functionality, if you are not familiar with it I would encourage you to check it out - <a href="https://nsubstitute.github.io/">https://nsubstitute.github.io/</a></p>
<div class="footnotes">
<hr>
<ol>
<li id="fn:1">
<p>I do try most of the time<a href="https://www.nyami.uk/#fnref:1" class="footnote-back-ref">↩</a></p>
</li>
</ol>
</div>
Something interesting for sure...
https://www.nyami.uk/posts/2022/2022-03-04-sln-wide-project-settings
Solution Wide Project Settings
2022-03-04T00:00:00Z
<p>When working with larger solutions in Visual Studio there often common properties you want to set across the board for all your project, for example <code>Copyright</code> or <code>TreatWarningsAsErrors</code>. It can be a little tedious to set these for all the projects, particularly for bigger solutions, and when you add new projects to your solution it's easily missed resulting in undesired differences between projects. A nice simple way to set common properties is to use <code>Directory.Build.props</code>.</p>
<!--more-->
<p>Simply create a new file, <code>Directory.Build.props</code>, at the root of your solution and populate it with the properties you wish to set, for example:</p>
<pre><code class="language-xml"><Project>
<PropertyGroup>
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
<Copyright>Douglas Cameron</Copyright>
</PropertyGroup>
</Project>
</code></pre>
<p>Now all projects under this folder will take on these properties, and they can be overridden, or indeed expanded with another <code>Directory.Build.props</code> within any subfolder (for example if your unit tests are under a test folder, you could create properties pertaining to these projects there), or via the actual project file.</p>
<p>You could also this file to add common NuGet packages to all your projects, for example if you used <a href="https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/overview#third-party-analyzers">3rd party analyzers</a> you could add these here along with any custom rules as required, however you will need to manage the version here and avoid using the NuGet package manager in Visual Studio as this will affect the actual project files.</p>
Something interesting for sure...
https://www.nyami.uk/posts/2020-05-04-unittestentitybuilder
Entity Builder for Unit Tests
2020-05-04T00:00:00Z
<p>If you find yourself needing to create an instance of a domain entity for unit testing, but having trouble getting round property or constructor accessability, using a builder is a great technique to get round this and provide a consistent, reusable method of creating the object for your tests.</p>
<!--more-->
<p>Typically you might find yourself creating opinionated constructors or getter only properties that will assert or support rules for an entity or business logic, but these can sometimes present a challenge when it comes to creating unit tests. Consider the following class:</p>
<pre><code>public class Foo
{
public enum StatusEnum
{
New = 0,
Open = 1,
Closed = 2
}
// Private constructor used by Entity Framework
private Foo() { }
// Used to create a new Foo
public Foo(string name)
{
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Name must not be empty", nameof(name));
this.Name = name;
this.Status = StatusEnum.New;
}
public string Name { get; private set; }
public StatusEnum Status { get; private set; }
public void Close() {
if (this.Status != StatusEnum.Open) throw new Exception($"{this.Name} must be open for it to be closed.");
this.Status = StatusEnum.Closed;
}
}
</code></pre>
<p>Here we have our Foo entity designed to assert a couple of things, firstly we can only set the name when creating the instance, and secondly we can only change the status to Closed if the status is currently Open. If we wanted to write a unit test around our <code>Close</code> method we might be tempted to change the accessability of our <code>Status</code> property, or even change the private constructor to allow us to create a usable entity in our test project, however both these actions might well lead to an API open to misuse.</p>
<p>A much better option would be to create a builder in our test project which can easily get round the constructor and property accessability and ensure some sort of consistency and reusability in our unit tests. Our builder for the class above might look a little like this:</p>
<pre><code>public class FooBuilder
{
private readonly Type entityType = typeof(Foo);
private readonly Foo foo;
public FooBuilder(string name)
{
var entity = Activator.CreateInstance(entityType, true) as Foo;
foo = entity ?? throw new ArgumentNullException(nameof(entity));
entityType.GetProperty(nameof(foo.Name)).SetValue(foo, name);
}
public FooBuilder WithStatus(StatusEnum status)
{
entityType.GetProperty(nameof(foo.Status)).SetValue(foo, status);
return this;
}
public Foo Build()
{
return foo;
}
}
</code></pre>
<p>We can now use this builder to create and bypass our assertions without compromising the design of our entity:</p>
<pre><code>var testFoo = new FooBuilder("wibble")
.WithStatus(StatusEnum.Open)
.Build();
</code></pre>
<p>This is not fool proof and still open for misuse, but at least most of the damage will confined to your test projects so it's a much better option compared to 'compromising' your API design.</p>
Something interesting for sure...
https://www.nyami.uk/posts/2019-06-11-vuewithaspnetpart3
VueJs and ASP.NET Core - Part 3
2019-06-11T00:00:00Z
<p>In parts <a href="https://www.nyami.uk/posts/2019-05-10-VueWithAspNetPart1">1</a> and <a href="https://www.nyami.uk/posts/2019-05-21-VueWithAspNetPart2">2</a> we looked at the experience of creating a new Angular app and some of the differences compared to what's required for Vue. We then went on to create middleware to add support for running the Vue CLI within our ASP.NET application, and then a new project enabling us to successfully run the Vue CLI in development and have the ability to package everything together when publishing our app. In this final part we are going to create a new project template allowing us a quick start for future projects.</p>
<!--more-->
<h2 id="creating-a-template">Creating a Template</h2>
<p>Newer versions of the .NET SDK has really simplified template creation, rather than detailing the whole experience here you are probably best referring to the <a href="https://docs.microsoft.com/en-us/dotnet/core/tutorials/create-custom-template">official documentation</a> however here is an overview of what I've done with a few handy pointers.</p>
<ol>
<li>Create an empty project based on the webapi template</li>
<li>Added the package created in Part 2 using <code>Install-Package Nyami.AspNetCore.VueCliServices</code></li>
<li>Created a ClientApp using the Vue CLI</li>
<li>Added the custom targets into the project file</li>
<li>Created the template configuration described <a href="https://docs.microsoft.com/en-us/dotnet/core/tutorials/create-custom-template#create-a-template-from-a-project">here</a>
<ol>
<li>When creating the template specify <code>sourceName</code>, this should match your root namespace and project file name, when a project is created from the template this will be replaced with the name</li>
<li><code>preferNameDirectory</code> was set to <code>true</code>, if no name is provided when the project is created the folder name will be used as the default name</li>
</ol>
</li>
<li>Made some minor changes to the wiring everything up in a more realistic way
<ol>
<li>Place holders for config</li>
<li>Add a call to the API from the Vue component</li>
</ol>
</li>
<li>Created nuspec file
<ol>
<li>Ensure the generated files (bin, obj, node_modules etc) were excluded from the package</li>
</ol>
</li>
<li>Published to NuGet</li>
</ol>
<p>This template can be pulled down from NuGet and installed using the command <code>dotnet new -i Nyami.AspNetCore.Vue.Template</code>, once installed you can create a new project using <code>dotnet new vue</code>.</p>
<h2 id="summary">Summary</h2>
<p>There are a number of ways to get Vue.js and ASP.NET working together but this approach to works really well allowing you to get up and running with minimal effort and take advantage of Vue's CLI along side Visual Studio's developer experience. I'm not expecting either packages to get a lot of use, they were mainly proving the concept, but if you end up using them and have problems or questions just reach out to me.</p>
Something interesting for sure...
https://www.nyami.uk/posts/2019-05-21-vuewithaspnetpart2
VueJs and ASP.NET Core - Part 2
2019-05-21T00:00:00Z
<p>In <a href="https://www.nyami.uk/posts/2019-05-10-VueWithAspNetPart1">Part 1</a> we looked at the Angular project template with ASP.NET Core and its pretty much what we want to achieve for VueJs. In this part we'll dig a little deeper into <a href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.spaservices?view=aspnetcore-2.2">Microsoft.AspNetCore.SpaServices</a>, specifically <a href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.spaservices.angularcli?view=aspnetcore-2.2">Microsoft.AspNetCore.SpaServices.AngularCli</a> and look to take inspiration for our Vue solution.</p>
<!--more-->
<h2 id="vue-create">vue create</h2>
<p>Let's start out by trying to use the template created for Angular and swap out the ClientApp for our VueJs app and see what happens.
First we'll create our VueJs application, to do this we'll use the <a href="https://cli.vuejs.org/">Vue CLI</a>, I've used npm to install this as a global tool (<code>npm install -g @vue/cli</code>), so it just a case of typing <code> vue create hello-world</code>, where hello-world is the name of your project, at a suitable location in your favourite command prompt. You'll then be prompted a present, I opted for manually selecting feature and chose:</p>
<ol>
<li>Babel, TypeScript, Linter/Formatter</li>
<li>Yes to Use class-style component syntax</li>
<li>Yes to Use Babel alongside TypeScript for auto-detected polyfills</li>
<li>TSLint as linter/formatter config</li>
<li>Lint on save</li>
<li>Config in dedicated config files</li>
</ol>
<p>We can have a look at our newly created site if we navigate into the folder and perform an <code>npm install</code> before running <code>npm run serve</code>, nothing exciting but it should all work.</p>
<h2 id="dotnet-new">dotnet new</h2>
<p>Next, we'll create an ASP.NET app using the Angular project template, again, at a suitable location in your favourite command prompt, type <code>dotnet new angular</code>. We can open the project and run this in Visual Studio, and as if by magic we have an Angular app running from our ASP.NET project. If we take a look at the build output we should be able to see that an 'npm install' was initiated, this was from the additional target 'DebugEnsureNodeEnv’ in our project file, and if you look though the output for “ASP.NET Core Web Server” you should see that 'ng serve' was called, this call was initiated by the <code>spa.UseAngularCliServer(npmScript: "start")</code> call in our startup.cs.</p>
<h2 id="bait-and-switch">bait and switch</h2>
<p>Now let's replace the Angular ClientApp folder with the contents from the VueJs app created above, and the change the npmScript called by <a href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.spaservices.angularcli.angularclimiddlewareextensions.useangularcliserver?view=aspnetcore-2.2">spa.UseAngularCliServer</a> in Startup.cs from "start" to "serve" and see what happens when we run the ASP.NET app.</p>
<h2 id="fail">fail</h2>
<p>Hmmmm.... not much, just the following exception:</p>
<pre><code>TimeoutException: The Angular CLI process did not start listening for requests within the timeout period of 50 seconds.
</code></pre>
<p>But if we take another look at the outputs, we can see that our project has installed the npm packages and has actually started our Vue application on a random port, it would appear that the middleware just hasn't hooked everything up. Thankfully Microsoft has open sourced ASP.NET Core and much of the supporting packages so it doesn’t take much to rummage around the source code for <a href="https://github.com/aspnet/AspNetCore/tree/master/src/Middleware/SpaServices.Extensions/src/AngularCli">AngularCliMiddleware</a> to realise that the magic to hook everything up is simply a regular expression looking for the confirmation from the Angular CLI output.</p>
<h2 id="vueclimiddleware">VueCliMiddleware</h2>
<p>So let's create our own middleware for Vue, looking though the source code it should be just a case of cloning the AngularCliMiddleware along with the internal supporting classes (unless of course you want to get creative with reflection) and use an appropriate regular expression to capture the Vue CLI start up.</p>
<ol>
<li>Create a new, empty class lib project</li>
<li>Add a package reference to <a href="https://www.nuget.org/packages/Microsoft.AspNetCore.SpaServices.Extensions/2.2.0">Microsoft.AspNetCore.SpaServices.Extensions (2.2.0)</a></li>
<li>Copy AngularCliBuilder.cs, AngularCliMiddleware.cs and AngularCliMiddlewareExtensions.cs and supporting internal classes from <a href="https://github.com/aspnet/AspNetCore">https://github.com/aspnet/AspNetCore</a></li>
<li>Rename all the things</li>
<li>Replace openBrowserLine Regex with a suitable Vue alternative, I went for <code>" - Local: (http\\S+)"</code></li>
</ol>
<p>You can now reference this project in any project created from the Angular template after swapping out the Angular ClientApp with you Vue ClientApp and simply change the <code>spa.UseAngularCliServer(npmScript: "start")</code> with <code>spa.UseVueCliServer(npmScript: "serve");</code></p>
<h2 id="heres-one-i-made-earlier">Here's one I made earlier</h2>
<p>You can check out the version I knocked up <a href="https://github.com/Nyami/AspNetCore.VueCliServices">here</a>, this has also been uploaded to <a href="https://www.nuget.org/packages/Nyami.AspNetCore.VueCliServices">NuGet</a> so you can get started by pulling this into your own project via the package manager UI or the package manager console using <code>Install-Package Nyami.AspNetCore.VueCliServices</code>.</p>
<p>In the <a href="https://www.nyami.uk/posts/2019-06-11-VueWithAspNetPart3">next part</a> we'll take a look at creating a project template to get us up and running even quicker.</p>
Something interesting for sure...
https://www.nyami.uk/posts/2019-05-10-vuewithaspnetpart1
VueJs and ASP.NET Core - Part 1
2019-05-10T00:00:00Z
<p>Whilst it’s relatively easy to <a href="http://lmgtfy.com/?q=asp.net+core+2+with+vue">find and follow a guide</a> to get up and running with Vue and ASP.NET Core, you’ll probably find there are a number techniques, methods, and opinions and there isn’t really the ‘first class’ support and 'simple' method of getting started as there is with Angular. In the following series of posts we’ll take a look at repurposing and using some of Microsoft’s SpaServices to create better support for Vue.js within your new ASP.NET Core project.</p>
<!--more-->
<h2 id="dotnet-new-angular">dotnet new angular</h2>
<p>Before we get started creating our own stuff for Vue lets look at creating an Angular project using the <a href="https://www.nuget.org/packages/Microsoft.DotNet.Web.Spa.ProjectTemplates/">Microsoft's template</a> and see what it gives us.</p>
<p>Assuming you have the <a href="https://dotnet.microsoft.com/download">.NET Core SDK</a> installed (tested with 2.2), at a location of your choosing, drop to your preferred terminal and type <code>dotnet new angular</code>. We now have a fairly sparse, and if you've worked with ASP.NET, familiar, project created. Let's break it down a little:</p>
<ul>
<li>ClientApp folder - a Hello World Angular app</li>
<li>Controllers folder - contains a simple api to 'fetch' weather data</li>
<li>Pages folder - not much here, just the Error page (MVC)</li>
<li>Properties folder - launchsettings used for debug/development</li>
<li>wwwroot folder - static assets for the side</li>
<li>appsettings.json - application setting, appsettings.development.json allows for development time settings</li>
<li>Foo.csproj - the aspnet project file, more information below</li>
<li>Program.cs - application entry point</li>
<li>Startup.cs - Configures services and application request pipeline</li>
</ul>
<p>If you want to learn more about ASP.NET Core apps the <a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/?view=aspnetcore-2.2">official documentation</a> is the best place to head.</p>
<h2 id="startup.cs">Startup.cs</h2>
<p>As with most ASP.NET applications the magic is coordinated in Startup.cs, there are typically two main parts, <code>ConfigureServices</code>, where we configure and register services required by our application, and <code>Configure</code>, where we configure the request handling pipeline. If you open Startup.cs you'll see the template has added some SPA related code to each of these methods.</p>
<p>In the first block of code, as well as adding MVC configuration, it adds configuration telling the middleware where to expect to find the files for the SPA application.</p>
<pre><code class="language-csharp">// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
// In production, the Angular files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/dist";
});
}
</code></pre>
<p>In this next block we can see there are two points of interest for our application, <code>app.UseSpaStaticFiles()</code>, which uses the configuration above to serve the static files for the SPA and <code>app.UseSpa</code> which will return the default SPA page for any unhandled requests, its important this is the last middleware in our pipeline as it essentially acts as a 'catch all' on the assumption the route will be matched by our client side app. You can also see that when in development there is a call <code>spa.UseAngularCliServer(npmScript: "start")</code>, this will call the npm script specified, wait for it to start successfully, and will 'proxy' calls in to the webpack web server started, and is what we'll go on to replicate for our Vue implementaion.</p>
<pre><code class="language-csharp">public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
// Code removed for brevity
app.UseSpaStaticFiles();
app.UseMvc(routes => {
//Code removed for brevity
});
app.UseSpa(spa =>
{
// To learn more about options for serving an Angular SPA from ASP.NET Core,
// see https://go.microsoft.com/fwlink/?linkid=864501
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseAngularCliServer(npmScript: "start");
}
});
}
</code></pre>
<h2 id="csproj-file">.csproj file</h2>
<p>The project file has a couple of extra targets when compared to a vanilla MVC project file, these are used to assert that npm has been installed when the project is being built and another target is used to add our Angular application to the published output. The project also ensures the ClientApp folder is not handled as part of the default build and publish behaviour.</p>
<h2 id="but-what-about-vue">But what about Vue?</h2>
<p>Looking at what Microsoft's template provides this is the exact experience we are hoping to achieve but for Vue. There are really two parts to the Angular and ASP.NET Core story, the SPA middleware that hooks up Webpack at development time and serves the SPA’s static files, and the template getting us up and running ensuring a consistent experience. In the next part we'll take a look at the middleware and see how far it can take us for Vue.</p>
<p><a href="https://www.nyami.uk/posts/2019-05-21-VueWithAspNetPart2">Part 2</a></p>
Something interesting for sure...
https://www.nyami.uk/posts/2019-05-03-mics-camera-action
Mics, Camera, Action!
2019-05-03T00:00:00Z
<p>At the end of last year we ran a successful <a href="https://www.gofundme.com/aberdeen-developers-net-user-group">funding campaign</a> at Aberdeen Developers .NET User Group to purchase some gear to allow us to record some of our sessions. We had a good idea of what we were wanting to achieve, essentially, we wanted to be able to publish recordings of our sessions and we weren’t wanting to spend hours processing the content after the recording. With a couple of events successfully in the bag I thought it might be worth sharing our setup, so here it is...</p>
<!--more-->
<p>Most of the magic is done using <a href="https://obsproject.com/">Open Broadcaster Software (OBS)</a>, a free and open-source streaming and recording program, but before we dive into our config let’s run down our hardware.</p>
<ul>
<li>Microphones, probably one of the most important things for me, personally I can’t follow any video with poor sound. We have a <a href="https://www.amazon.co.uk/gp/product/B07F3KLX14">wireless lapel mic</a> for the speaker and a <a href="https://www.amazon.co.uk/gp/product/B07F3V3LD2">wireless handheld mic</a> for the host</li>
<li><a href="https://www.amazon.co.uk/gp/product/B01DRWCOGA">Elgato Game Capture HD60 S</a>, this is an awesome bit of kit, it allows us to capture the output from the presenter's laptop without having to install anything on their laptop, we also have an HDMI splitter just in case any DRM protection interferes with the process, but we've not encountered this</li>
<li><a href="https://www.amazon.co.uk/gp/product/B006A2Q81M">Logitech C920 HD Pro Webcam</a> mounted on a tripod just to make things a little more interesting to watch</li>
<li><a href="https://www.amazon.co.uk/gp/product/B06W2KLM3S">Elgato Stream Deck</a> to make scene selection nice and simple</li>
<li>A good selection of cables, USB, HDMI and power cables as well as a USB hub to keep thing tidy</li>
</ul>
<img src="/images/ADNUGRecordingGear.jpg" alt="A selection of stuff" style="width:250px;"/>
<p>As mentioned above OBS provides much of the magic, each of the input sources above can be toggled in OBS. We have 3 different scenes; presentation, web cam directed at the speaker, and a composite of the two, which we can cycle through depending on how the presentation is going, we can also toggle each of the microphones as required. OBS can record and stream via two separate controls within the application, we have OBS setup to stream to <a href="https://www.twitch.tv/adnuguk">Twitch</a> and record to disc, thankfully both have worked well on the night. Once recorded we only have to put the recording though ffmpeg trimming as required before uploading to our <a href="https://www.youtube.com/channel/UCRnxcmrSrc4TWKqakE4EViw">YouTube channel</a>.</p>
<p>We'll hopefully get a few more sessions recorded so make sure subscribe to <a href="https://www.youtube.com/channel/UCRnxcmrSrc4TWKqakE4EViw">YouTube channel</a> so you don't miss out. If you are interested in setting something similar up and have questions please reach out if I can be of any help.</p>
Something interesting for sure...
https://www.nyami.uk/posts/2019-03-03-custom-http-verb
Custom HTTP Verb
2019-03-03T00:00:00Z
<p>There are server reasons you might look to implement a custom HTTP Verb in you ASP.NET application, and thankfully with ASP.NET Core it’s incredibly simple.</p>
<!--more-->
<p>Here is a nice simple example of a WEBDAV inspired SEARCH verb, potentially useful if you’re encountering limitations of GET, perhaps because you can't have a GET with body, hitting the URL length limit, or just want to have consistent verb.</p>
<pre><code>public class HttpSearchAttribute : HttpMethodAttribute {
private static readonly IEnumerable<string> SupportedMethods = new[] { "SEARCH" };
public HttpSearchAttribute() : base(SupportedMethods) {
}
public HttpSearchAttribute(string template) : base(SupportedMethods, template) {
if (string.IsNullOrWhiteSpace(template)) {
throw new ArgumentNullException(nameof(template));
}
}
}
</code></pre>
<p>Once you have your custom attribute you can apply this to any controller action and start using your verb.</p>
<pre><code>// SEARCH api/values
[HttpSearch]
public ActionResult<IEnumerable<string>> Search([FromBody] string value) {
return values.Where(v => v.Contains(value)).ToList();
}
</code></pre>
<p>A fully working, simple example is located over at <a href="https://github.com/Nyami/WebApiSearchMethod">GitHub</a></p>
Something interesting for sure...
https://www.nyami.uk/posts/2019-03-02-blog-20
Blog 2.0
2019-03-02T00:00:00Z
<p>I think I have more blog post about setting up blogs than I have on anything else, and its been a while since the last one so I thought it about time for another one. I like the concept of static generation for blogs and first incarnations used Octopress, a blogging framework based on Jekyll, but the workflow and content produced wasn’t really working for me so it was time for a change.</p>
<!--more-->
<p>I decided to look at <a href="https://wyam.io/">Wyam</a>, I knew of a few folks using it and as it using .NET and Razor much of it had a familiar feel I was comfortable with. I’m not going to go into detail on setting it up, their site has comprehensive coverage on <a href="https://wyam.io/docs/usage/">getting started</a>, using <a href="https://wyam.io/docs/deployment/appveyor">Github Pages and AppVeyor</a> for deployment. I did start off trying to be smart and automate the markdown conversion but the reality was I didn’t have much so opted for the manual approach. Hopefully I’ll have a couple of useful posts before the next blog post and blogs posts.</p>
Something interesting for sure...
https://www.nyami.uk/posts/2018-08-17-dotnet-sln-add
dotnet sln add
2018-08-17T09:02:03Z
<p>It's been a while since I'd created a number dotnet projects and supporting solution using the command line so I had to refer to the <a href="https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet">documentation</a> to keep me right. As I had just created a number of projects adding each one to the solution is a little tedious so when I'd spotted I could use <a href="https://en.wikipedia.org/wiki/Glob_(programming)">globbing patterns</a> I thought this would save time and a few key presses.</p>
<!--more-->
<p>However, when I ran <code>dotnet sln Foo.sln add **/*.csproj</code> I was presented with the error <code>Could not find project or directory **/*.csproj</code>. It turns out that globbing is not actually supported by the CLI but actually a shell feature and PowerShell wasn't expanding the glob. Luckly as dotnet is cross platform and I have <a href="https://docs.microsoft.com/en-us/windows/wsl/install-win10">Windows Subsystem for Linux</a> installed with all the dotnet goodness I could switch to <code>bash</code>, ensure globbing was enabled using <code>shopt -s globstar</code>, and then run <code>dotnet sln Foo.sln add **/*.csproj</code> to add all my new projects, job done...</p>
Something interesting for sure...