 <?xml-stylesheet type="text/css" href="https://www.esdm.co.uk/Data/style/rss1.css" ?> <?xml-stylesheet type="text/xsl" href="https://www.esdm.co.uk/Data/style/rss1.xsl" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd">
  <channel>
    <title>The knowledge base blog</title>
    <link>https://www.esdm.co.uk/knowledge</link>
    <description />
    <docs>http://www.rssboard.org/rss-specification</docs>
    <generator>mojoPortal Blog Module</generator>
    <language>en-GB</language>
    <ttl>120</ttl>
    <atom:link href="https://www.esdm.co.uk/Blog/RSS.aspx?p=138~108~196" rel="self" type="application/rss+xml" />
    <itunes:owner />
    <itunes:explicit>no</itunes:explicit>
    <item>
      <title>When MapServer refuses to run in an ASP.NET Core MVC site (401 - unauthorized)</title>
      <description><![CDATA[<p>Well that was two hours I won’t get back, but I’ll make a note here in case it helps anyone else. I had simply overlooked one of those many tiny things…</p><p>We use MapServer as a lightweight GIS engine in many of our products, giving us WMS/WFS API endpoints for a wide range of purposes. When upgrading the <a href="https://colchesterheritage.co.uk" target="_blank">Colchester Heritage Explorer website</a>, an ASP.NET Core MVC site made with <a href="https://www.cloudscribe.com" target="_blank">cloudscribe</a> and <a href="https://hbsmrdocumentation.esdm.co.uk/hbsmr-webapi" target="_blank">HBSMR WEB/API</a> components, I dived in to configure and test the MapServer instance. I followed our usual processes, enabled the CGI extension to execute, setting folder permissions to allow MapServer to write out log files, configured our secure MapServer Proxy component, etc. </p><p>But it wasn’t working. </p><p>One of our first tests of a MapServer instance is to browse to the location of the main MapServer executable, in this case the address was:</p><p>https://colchesterheritage.co.uk/wwwroot/MapServer/Scripts/mapserv.exe </p><p>but instead of a nice diagnostic response, I got “401 – Unauthorized: Access is denied due to invalid credentials”:</p><p><img width="640" height="116" title="image" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="image" src="https://www.esdm.co.uk/Data/Sites/1/media/wlw/image_160.png" border="0"></p><p>This was very puzzling, as I already had this working perfectly in a parallel test site, on the same server with identical configuration in every respect – or so I thought. Both sites were using an application pool with Identity set to ApplicationPoolIdentity, folder permissions were all good for this identity, there were no ip restrictions, and no reason I could see for it not to work.</p><p>Except that I’d forgotten about the Anonymous Authentication Credentials… in IIS select the site &gt; Authentication &gt; select Anonymous Authentication and click “Edit…” &gt; I found the default setting:</p><p><img width="640" height="328" title="image" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="image" src="https://www.esdm.co.uk/Data/Sites/1/media/wlw/image_161.png" border="0"></p><p>And of course I had not set up permissions for this user to access the location of the MapServer files. So there are two solutions: a) <em>less preferred</em>: add the IUSR account at the root of site with default permissions:</p><p><img width="378" height="457" title="image" style="margin: 0px; border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="image" src="https://www.esdm.co.uk/Data/Sites/1/media/wlw/image_162.png" border="0"></p><p>(if I were using this solution I would also tick “Deny” for the “Write” setting off bottom of that image);</p><p>or b) <em>preferred</em>: change the Anonymous Authentication Credentials for the site to the Application pool identity:</p><p><img width="640" height="330" title="image" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="image" src="https://www.esdm.co.uk/Data/Sites/1/media/wlw/image_163.png" border="0"></p><p>After making this change, on browsing to our MapServer executable I saw the expected response “Noquery information to decode. QUERY_STRING is set, but empty. ” which means the CGI application is working. </p><p><strong>Phew – problem solved!</strong></p><p>My next step in hardening this site is to block this direct access, and route all requests through a secured proxy, so the above URL to the exe won’t work by the time you read this if we’ve done our security right.</p><p>To see the working result, check out the maps within the <a href="https://colchesterheritage.co.uk" target="_blank">Colchester Heritage Explorer</a>, for example this map of the historic buildings and sites that are <a href="https://colchesterheritage.co.uk/map?center=100120.11461153519,6780076.084676751&amp;zoom=16&amp;baselayer=OpenStreetMap&amp;opacity=1&amp;panel=overlays&amp;overlays=LocalList&amp;overlaysoff=RegisteredParksAndGardens,ConservationAreas,ListedBuildings,ScheduledMonuments,Events,Monuments" target="_blank">included on the Colchester “Local List”</a>.</p><p>And here’s a rather nice map of WW2 pillboxes and related defensive sites around Colchester, generated by a MapServer WFS request in response to a <a href="https://colchesterheritage.co.uk/globalsearch/index?q=pillboxes" target="_blank">a free text search on “pillboxes”</a>:</p><p><img width="559" height="480" title="image" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="image" src="https://www.esdm.co.uk/Data/Sites/1/media/wlw/image_164.png" border="0"></p><p>I hope this helps someone, and please feel free to add comments below.</p><br /><a href='https://www.esdm.co.uk/when-mapserver-refuses-to-run-in-an-aspnet-core-mvc-site-401-unauthorized'>Crispin Flower</a>&nbsp;&nbsp;<a href='https://www.esdm.co.uk/when-mapserver-refuses-to-run-in-an-aspnet-core-mvc-site-401-unauthorized'>...</a>]]></description>
      <link>https://www.esdm.co.uk/when-mapserver-refuses-to-run-in-an-aspnet-core-mvc-site-401-unauthorized</link>
      <author>crispin.flower@idoxgroup.com (Crispin Flower)</author>
      <comments>https://www.esdm.co.uk/when-mapserver-refuses-to-run-in-an-aspnet-core-mvc-site-401-unauthorized</comments>
      <guid isPermaLink="true">https://www.esdm.co.uk/when-mapserver-refuses-to-run-in-an-aspnet-core-mvc-site-401-unauthorized</guid>
      <pubDate>Sat, 19 Oct 2019 10:55:24 GMT</pubDate>
    </item>
    <item>
      <title>Using cloudscribe with Identity Server 4 with a SQL Server store on .Net Core 2 MVC securing APIs</title>
      <description><![CDATA[<p>Well that’s a bit of a mouthful of a title – but it does describe what I was trying to do, and I didn’t find it easy. It’s not that complicated when you know how, but there are an awful lot of options and it wasn’t clear (to me at least) which ones to pick, so I hope this saves others some time.</p>

<h4>Aim</h4>

<p>I wanted a <a href="https://www.cloudscribe.com/">cloudscribe</a> site running allowing users to be able to logon as usual using cookies, but I also wanted to have an API that could be secured for clients external to the site without having to use the cookie login and I wanted to use Identity Server 4 with a SQL data store.</p>

<h3>Starting setup</h3>

<h4>Server</h4>

<p>I used Joe Audette's excellent cloudscribe Visual Studio template <a href="https://www.cloudscribe.com/blog/2017/09/11/announcing-cloudscribe-project-templates">https://www.cloudscribe.com/blog/2017/09/11/announcing-cloudscribe-project-templates</a> and selected use MSSQL Server and the Include Identity Server integration option. Also selecting the 2 options in the “Expert Zone” gave me an example API to test with.</p>

<p><a href="https://www.esdm.co.uk/Data/Sites/1/media/wlw/clip_image002_8.jpg"><img alt="clip_image002" border="0" height="244" src="https://www.esdm.co.uk/Data/Sites/1/media/wlw/clip_image002_thumb_7.jpg" style="margin: 0px; display: inline; background-image: none;" title="clip_image002" width="227" /></a></p>

<p>This gave me the basic website and was the one I wanted to add the secured API into. The VS project has a weather forecast API as an example.</p>

<h4>Client</h4>

<p>I then setup a separate MVC project using a basic template to act as the client application. This was all done using Visual Studio 2017 and .Net Core 2.</p>

<h3>Server application</h3>

<p>By default, the weather forecast API is accessible to all users. Try: http://localhost:35668/api/SampleData/WeatherForecasts</p>

<p>You can secure this by adding the [Authorize] statement to the API on the SampleDataController.cs page e.g.</p>

<div id="codeSnippetWrapper">
<pre id="codeSnippet" style="margin: 0em; padding: 0px; width: 100%; text-align: left; color: black; line-height: 12pt; overflow: visible; font-family: &quot;Courier New&quot;, courier, monospace; font-size: 8pt; direction: ltr; background-color: rgb(244, 244, 244);">
[Authorize]
[HttpGet(<span style="color: rgb(0, 96, 128);">"[action]"</span>)]
<span style="color: rgb(0, 0, 255);">public</span> IEnumerable&lt;WeatherForecast&gt; WeatherForecasts()
{
    var rng = <span style="color: rgb(0, 0, 255);">new</span> Random();</pre>
</div>

<p>but you will find this presents the standard cloudscribe logon screen to access it – not exactly what’s wanted for an API.</p>

<p>In order to solve this we need to use JWT authorisation alongside the standard cookie authentication, but tell the API to only secure using the JWT authorisation . This is done by filtering the authentication scheme used by the Authorize statement as below (you will probably have to add the following assemblies to your code)</p>

<div id="codeSnippetWrapper">
<pre id="codeSnippet" style="margin: 0em; padding: 0px; width: 100%; text-align: left; color: black; line-height: 12pt; overflow: visible; font-family: &quot;Courier New&quot;, courier, monospace; font-size: 8pt; direction: ltr; background-color: rgb(244, 244, 244);">
<span style="color: rgb(0, 0, 255);">using</span> Microsoft.AspNetCore.Authorization;
<span style="color: rgb(0, 0, 255);">using</span> Microsoft.AspNetCore.Authentication.JwtBearer;</pre>
</div>

<p>and then add the filter to the authorize statement.</p>

<div id="codeSnippetWrapper">
<pre id="codeSnippet" style="margin: 0em; padding: 0px; width: 100%; text-align: left; color: black; line-height: 12pt; overflow: visible; font-family: &quot;Courier New&quot;, courier, monospace; font-size: 8pt; direction: ltr; background-color: rgb(244, 244, 244);">
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[HttpGet(<span style="color: rgb(0, 96, 128);">"[action]"</span>)]
<span style="color: rgb(0, 0, 255);">public</span> IEnumerable&lt;WeatherForecast&gt; WeatherForecasts()
{
    var rng = <span style="color: rgb(0, 0, 255);">new</span> Random();</pre>
</div>

<p>We have now told the API to authenticate using JWTBearer but we haven’t yet added JWT authentication to our applications pipeline. So in the startup.cs page we need to add in some assemblies:</p>

<div id="codeSnippetWrapper">
<pre id="codeSnippet" style="margin: 0em; padding: 0px; width: 100%; text-align: left; color: black; line-height: 12pt; overflow: visible; font-family: &quot;Courier New&quot;, courier, monospace; font-size: 8pt; direction: ltr; background-color: rgb(244, 244, 244);">
<span style="color: rgb(0, 0, 255);">using</span> Microsoft.AspNetCore.Authentication.JwtBearer;</pre>
</div>

<p>and then add the JWT service into the ConfigureServices method. (I added the statement below just above services.AddCors(options =&gt;)</p>

<div id="codeSnippetWrapper">
<pre id="codeSnippet" style="margin: 0em; padding: 0px; width: 100%; text-align: left; color: black; line-height: 12pt; overflow: visible; font-family: &quot;Courier New&quot;, courier, monospace; font-size: 8pt; direction: ltr; background-color: rgb(244, 244, 244);">
services.AddAuthentication(options =&gt;
{
    options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})

.AddJwtBearer(options =&gt;
{
    options.Authority = <span style="color: rgb(0, 96, 128);">"http://localhost:35668"</span>; <span style="color: rgb(0, 128, 0);">//No trailing /</span>
    options.Audience = <span style="color: rgb(0, 96, 128);">"api2"</span>; <span style="color: rgb(0, 128, 0);">//Name of api</span>
    options.RequireHttpsMetadata = <span style="color: rgb(0, 0, 255);">false</span>;

});</pre>
</div>

<p>Where:</p>

<p>.Authority is the address of the website with the api (note no trailing slash)</p>

<p>.Audience is the name you have given to the api in the Identity server 4 security setup (see more details below)</p>

<p>And then we need to tell our pipeline to use Authentication. So add the app.UseAuthentication() into the end of the ConfigureServices method just above the UseMVC call</p>

<div id="codeSnippetWrapper">
<pre id="codeSnippet" style="margin: 0em; padding: 0px; width: 100%; text-align: left; color: black; line-height: 12pt; overflow: visible; font-family: &quot;Courier New&quot;, courier, monospace; font-size: 8pt; direction: ltr; background-color: rgb(244, 244, 244);">
app.UseAuthentication();
UseMvc(app, multiTenantOptions.Mode == cloudscribe.Core.Models.MultiTenantMode.FolderName);</pre>
</div>

<p>Now if you try and access the api -&nbsp;http://localhost:35668/api/SampleData/WeatherForecasts&nbsp;- you should get an unauthorised message - even if you are logged onto the cloudscribe site using cookie authentication.</p>

<h3>Identity Server 4 configuration (through cloudscribe)</h3>

<p>Identity server has many options – which can be bewildering to start with. Full documentation is here: <a href="https://identityserver4.readthedocs.io/">https://identityserver4.readthedocs.io/</a></p>

<p>For our purposes here – I’m outlining the bare minimum that we need to setup security for our API, either using:</p>

<p>· A client credential using a secret</p>

<p>· A username and password</p>

<h4>API resources</h4>

<p>Under the admin menu in cloudscribe select security settings / API resources and create a new API record giving it a name (e.g. api2) making sure it matches the name you entered as the .Audience in the startup.cs .</p>

<p>Then we need to add a single scope record – called “allowapi2” in this example.</p>

<p><a href="https://www.esdm.co.uk/Data/Sites/1/media/wlw/clip_image004_5.jpg"><img alt="clip_image004" border="0" height="155" src="https://www.esdm.co.uk/Data/Sites/1/media/wlw/clip_image004_thumb_5.jpg" style="margin: 0px; display: inline; background-image: none;" title="clip_image004" width="244" /></a></p>

<h4>Client resources</h4>

<p>Under the admin menu in cloudscribe select security settings / API Clients and create a new client (I’ve called it client2 – remember this name for when we make the call from the client application). Edit the new client record and add:</p>

<p>· Allowed Scope record – e.g. allowapi2 – this must match the scope we entered for the api and is used to specify which apis this client can access</p>

<p><a href="https://www.esdm.co.uk/Data/Sites/1/media/wlw/clip_image006_3.jpg"><img alt="clip_image006" border="0" height="86" src="https://www.esdm.co.uk/Data/Sites/1/media/wlw/clip_image006_thumb_3.jpg" style="margin: 0px; display: inline; background-image: none;" title="clip_image006" width="214" /></a></p>

<p>· Client Secrets – the value is the SHA56 value of the secret we wish to use (in this example secret2) <s>– at the moment the cloudscribe interface doesn’t do this conversion for us so we have to do it manually somewhere&nbsp;(e.g. I used string s = "secret2".ToSha256();)&nbsp; &nbsp;</s></p>

<p><s>I added the secret using the web page and then pasted the converted secret direct into the relevant field in the record in the csids_ClientSecrets table in the database - but I think it would work equally well just pasting the converted value into the web page.</s></p>

<p><s>.ToSha256() is a string extension method&nbsp;in the IdentityModel assembly - this seems to do more than simply convert to sha256 - see&nbsp;<a href="https://github.com/IdentityModel/IdentityModel/blob/master/source/IdentityModel.Net45/Extensions/HashStringExtensions.cs">https://github.com/IdentityModel/IdentityModel/blob/master/source/IdentityModel.Net45/Extensions/HashStringExtensions.cs</a>.</s></p>

<p><s>It’s important that we set the secret type as well – in our example here it must be “SharedSecret”</s></p>

<p>Joe Audette has updated his nuget packages so saving a client secret now gives you a range of options for the secret type - in our example we need to pick "SharedSecret" and select to encrypt using Sha256 (see Joe's post in comments below for other options) which should make things easier.</p>

<p><a href="https://www.esdm.co.uk/Data/Sites/1/media/wlw/clip_image008_1.jpg"><img alt="clip_image008" border="0" height="68" src="https://www.esdm.co.uk/Data/Sites/1/media/wlw/clip_image008_thumb_1.jpg" style="margin: 0px; display: inline; background-image: none;" title="clip_image008" width="244" /></a></p>

<p>· Allowed Grant types – we are entering “password” and “client_credentials”. These determine how we can authenticate from the client app as we see below in the next section. Password means that authentication can use a username / pwd combination (i.e. a cloudscribe login). Client_credentials means we can login using a client secret and don’t have to be a known user on the site.</p>

<p><a href="https://www.esdm.co.uk/Data/Sites/1/media/wlw/clip_image010_1.jpg"><img alt="clip_image010" border="0" height="81" src="https://www.esdm.co.uk/Data/Sites/1/media/wlw/clip_image010_thumb_1.jpg" style="display: inline; background-image: none;" title="clip_image010" width="200" /></a></p>

<h3>Client application</h3>

<p>To connect securely to the API using a client connection with a secret use:</p>

<div id="codeSnippetWrapper">
<pre id="codeSnippet" style="margin: 0em; padding: 0px; width: 100%; text-align: left; color: black; line-height: 12pt; overflow: visible; font-family: &quot;Courier New&quot;, courier, monospace; font-size: 8pt; direction: ltr; background-color: rgb(244, 244, 244);">
var tokenClient = <span style="color: rgb(0, 0, 255);">new</span> TokenClient(disco.TokenEndpoint, <span style="color: rgb(0, 96, 128);">"client2"</span>, <span style="color: rgb(0, 96, 128);">"secret2"</span>);</pre>
</div>

<p>To connect using a username and password use:</p>

<div id="codeSnippetWrapper">
<pre id="codeSnippet" style="margin: 0em; padding: 0px; width: 100%; text-align: left; color: black; line-height: 12pt; overflow: visible; font-family: &quot;Courier New&quot;, courier, monospace; font-size: 8pt; direction: ltr; background-color: rgb(244, 244, 244);">
var tokenResponsePassword = await tokenClient.RequestResourceOwnerPasswordAsync(<span style="color: rgb(0, 96, 128);">"admin"</span>, <span style="color: rgb(0, 96, 128);">"admin"</span>, <span style="color: rgb(0, 96, 128);">"allowapi2"</span>);</pre>
</div>

<p>Note that the user name is the user name not the email which can be used to login interactively.</p>

<p>The whole method in the controller looked something like this – the rest of the code is deserializing the JSON return from the API and putting it into an object that can be displayed on a view page</p>

<div id="codeSnippetWrapper">
<pre id="codeSnippet" style="margin: 0em; padding: 0px; width: 100%; text-align: left; color: black; line-height: 12pt; overflow: visible; font-family: &quot;Courier New&quot;, courier, monospace; font-size: 8pt; direction: ltr; background-color: rgb(244, 244, 244);">
<span style="color: rgb(0, 0, 255);">using</span> System;
<span style="color: rgb(0, 0, 255);">using</span> System.Collections.Generic;
<span style="color: rgb(0, 0, 255);">using</span> System.Diagnostics;
<span style="color: rgb(0, 0, 255);">using</span> System.Threading.Tasks;
<span style="color: rgb(0, 0, 255);">using</span> Microsoft.AspNetCore.Mvc;
<span style="color: rgb(0, 0, 255);">using</span> ESDM.Models;
<span style="color: rgb(0, 0, 255);">using</span> System.Net.Http;
<span style="color: rgb(0, 0, 255);">using</span> Newtonsoft.Json;
<span style="color: rgb(0, 0, 255);">using</span> IdentityModel.Client;
<span style="color: rgb(0, 0, 255);">using</span> IdentityServerClient.Models;
<span style="color: rgb(0, 0, 255);">using</span> IdentityModel;</pre>
</div>

<p>and then</p>

<div id="codeSnippetWrapper">
<pre id="codeSnippet" style="margin: 0em; padding: 0px; width: 100%; text-align: left; color: black; line-height: 12pt; overflow: visible; font-family: &quot;Courier New&quot;, courier, monospace; font-size: 8pt; direction: ltr; background-color: rgb(244, 244, 244);">
<span style="color: rgb(0, 128, 0);">//Hosted web API REST Service base url  </span>
<span style="color: rgb(0, 0, 255);">string</span> Baseurl = <span style="color: rgb(0, 96, 128);">"http://localhost:35668"</span>;

<span style="color: rgb(0, 0, 255);">public</span> async Task&lt;ActionResult&gt; Index()
{
    List&lt;WeatherForecast&gt; ans = <span style="color: rgb(0, 0, 255);">new</span> List&lt;WeatherForecast&gt;();
     <span style="color: rgb(0, 0, 255);">using</span> (var client = <span style="color: rgb(0, 0, 255);">new</span> HttpClient())
    {
        <span style="color: rgb(0, 128, 0);">// discover endpoints from metadata</span>
        var disco = await DiscoveryClient.GetAsync(Baseurl);
        var tokenClient = <span style="color: rgb(0, 0, 255);">new</span> TokenClient(disco.TokenEndpoint, <span style="color: rgb(0, 96, 128);">"client2"</span>, <span style="color: rgb(0, 96, 128);">"secret2"</span>);
        var tokenResponse = await tokenClient.RequestClientCredentialsAsync(<span style="color: rgb(0, 96, 128);">"allowapi2"</span>);

<span style="color: rgb(0, 128, 0);">//Example getting alternative token if you want to use username / pwd </span>
        var tokenResponsePassword = await tokenClient.RequestResourceOwnerPasswordAsync(<span style="color: rgb(0, 96, 128);">"admin"</span>, <span style="color: rgb(0, 96, 128);">"admin"</span>, <span style="color: rgb(0, 96, 128);">"allowapi2"</span>);

        <span style="color: rgb(0, 128, 0);">// call api - change for tokenResponsePassword if you want to use username / pwd</span>
        client.SetBearerToken(tokenResponse.AccessToken);

        var response = await client.GetAsync(Baseurl + <span style="color: rgb(0, 96, 128);">"/api/SampleData/WeatherForecasts"</span>);
        <span style="color: rgb(0, 0, 255);">if</span> (response.IsSuccessStatusCode)
        {
            var content =  response.Content.ReadAsStringAsync().Result;
            ans = JsonConvert.DeserializeObject&lt;List&lt;WeatherForecast&gt;&gt;(content);
        }
        <span style="color: rgb(0, 0, 255);">return</span> View(ans);
    }</pre>
</div>

<p>The model for the forecast data was:</p>

<div id="codeSnippetWrapper">
<pre id="codeSnippet" style="margin: 0em; padding: 0px; width: 100%; text-align: left; color: black; line-height: 12pt; overflow: visible; font-family: &quot;Courier New&quot;, courier, monospace; font-size: 8pt; direction: ltr; background-color: rgb(244, 244, 244);">
<span style="color: rgb(0, 0, 255);">namespace</span> ESDM.Models
{
    <span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">partial</span> <span style="color: rgb(0, 0, 255);">class</span> WeatherForecast
    {
        <span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">string</span> DateFormatted { get; set; }
        <span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">int</span> TemperatureC { get; set; }
        <span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">string</span> Summary { get; set; }

        <span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">int</span> TemperatureF
        {
            get
            {
                <span style="color: rgb(0, 0, 255);">return</span> 32 + (<span style="color: rgb(0, 0, 255);">int</span>)(TemperatureC / 0.5556);
            }
        }
    }
}
</pre>
</div>

<p>And my view contained</p>

<div id="codeSnippetWrapper">
<pre id="codeSnippet" style="margin: 0em; padding: 0px; width: 100%; text-align: left; color: black; line-height: 12pt; overflow: visible; font-family: &quot;Courier New&quot;, courier, monospace; font-size: 8pt; direction: ltr; background-color: rgb(244, 244, 244);">
@model IEnumerable&lt;ESDM.Models.WeatherForecast&gt;
&lt;div&gt;
    &lt;ul&gt;
        @<span style="color: rgb(0, 0, 255);">foreach</span> (var forecast <span style="color: rgb(0, 0, 255);">in</span> Model)
        {
            &lt;li&gt;@forecast.Summary&lt;/li&gt;
        }
    &lt;/ul&gt;
&lt;/div&gt;</pre>
</div>
<br /><a href='https://www.esdm.co.uk/using-cloudscribe-with-identity-server-4-with-a-sql-server-store-on-net-core-2-mvc-securing-apis'></a>&nbsp;&nbsp;<a href='https://www.esdm.co.uk/using-cloudscribe-with-identity-server-4-with-a-sql-server-store-on-net-core-2-mvc-securing-apis'>...</a>]]></description>
      <link>https://www.esdm.co.uk/using-cloudscribe-with-identity-server-4-with-a-sql-server-store-on-net-core-2-mvc-securing-apis</link>
      <author>()</author>
      <comments>https://www.esdm.co.uk/using-cloudscribe-with-identity-server-4-with-a-sql-server-store-on-net-core-2-mvc-securing-apis</comments>
      <guid isPermaLink="true">https://www.esdm.co.uk/using-cloudscribe-with-identity-server-4-with-a-sql-server-store-on-net-core-2-mvc-securing-apis</guid>
      <pubDate>Fri, 03 Nov 2017 22:14:00 GMT</pubDate>
    </item>
  </channel>
</rss>