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

<channel>
	<title>Sergey Barskiy&#8217;s Blog</title>
	<atom:link href="http://www.dotnetspeak.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.dotnetspeak.com</link>
	<description>Software Development Thoughts</description>
	<lastBuildDate>Fri, 16 Sep 2022 01:17:10 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=5.6.14</generator>
	<item>
		<title>Using Async Enumerable To Save Memory</title>
		<link>http://www.dotnetspeak.com/uncategorized/using-async-enumerable-to-save-memory/</link>
					<comments>http://www.dotnetspeak.com/uncategorized/using-async-enumerable-to-save-memory/#comments</comments>
		
		<dc:creator><![CDATA[Sergey Barskiy]]></dc:creator>
		<pubDate>Fri, 16 Sep 2022 01:17:10 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[.NET Core]]></category>
		<category><![CDATA[asp.net core]]></category>
		<guid isPermaLink="false">http://www.dotnetspeak.com/?p=1480</guid>

					<description><![CDATA[I have encountered a problem recently. We have feature in the software that allows users to download large amounts of exported data. We found that some users selected so much data that the memory grew uncontrollably in .NET Core. So I researched the problem and found out that the async enumerable feature in C# 8 ...</p><p><a href="http://www.dotnetspeak.com/uncategorized/using-async-enumerable-to-save-memory/" class="more-link">Continue reading &#8216;Using Async Enumerable To Save Memory&#8217; &#187;</a>]]></description>
										<content:encoded><![CDATA[
<p>I have encountered a problem recently.  We have feature in the software that allows users to download large amounts of exported data.  We found that some users selected so much data that the memory grew uncontrollably in .NET Core.  So I researched the problem and found out that the <a href="https://docs.microsoft.com/en-us/archive/msdn-magazine/2019/november/csharp-iterating-with-async-enumerables-in-csharp-8" data-type="URL" data-id="https://docs.microsoft.com/en-us/archive/msdn-magazine/2019/november/csharp-iterating-with-async-enumerables-in-csharp-8" target="_blank" rel="noreferrer noopener">async enumerable feature in C# 8</a> could solve the issue for me.</p>



<p>Here is how I could reproduce the problem in a controller.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: csharp; title: ; notranslate">
&#91;ApiController]
&#91;Route(&quot;&#91;controller]&quot;)]
public class StreamingController : ControllerBase
{
    private readonly ILogger&lt;StreamingController&gt; _logger;

    public StreamingController(ILogger&lt;StreamingController&gt; logger)
    {
        _logger = logger;
    }

    &#91;HttpGet]
    &#91;Route(&quot;async&quot;)]
    public IAsyncEnumerable&lt;string&gt; Get()
    {
        Response.Clear();
        Response.Headers.Add(&quot;Content-Disposition&quot;, &quot;attachment;filename=somenameasync.csv&quot;);
        Response.Headers.Add(&quot;Content-Transfer-Encoding&quot;, &quot;binary&quot;);
        return GetAsyncContent();
    }

    private IEnumerable&lt;string&gt; GetSyncContent()
    {
        var strings = new List&lt;string&gt;();
        for (int i = 0; i &lt; 1000; i++)
        {
            strings.Add(Guid.NewGuid().ToString().PadRight(1000000) + Environment.NewLine);
        }

        return strings;
    }
}
</pre></div>


<p>If you run this code, you will see your process hitting 4 GB of RAM.  Not an ideal situation for about 1 GB export file.  So the solution is to use async enumerable and literally stream the data into the browser.  Here is the final version of the same controller</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: csharp; title: ; notranslate">
&#91;ApiController]
&#91;Route(&quot;&#91;controller]&quot;)]
public class StreamingController : ControllerBase
{
    private readonly ILogger&lt;StreamingController&gt; _logger;

    public StreamingController(ILogger&lt;StreamingController&gt; logger)
    {
        _logger = logger;
    }

    &#91;HttpGet]
    &#91;Route(&quot;async&quot;)]
    public IAsyncEnumerable&lt;string&gt; Get()
    {
        Response.Clear();
        Response.Headers.Add(&quot;Content-Disposition&quot;, &quot;attachment;filename=somenameasync.csv&quot;);
        Response.Headers.Add(&quot;Content-Transfer-Encoding&quot;, &quot;binary&quot;);
        return GetAsyncContent();
    }

    &#91;HttpGet]
    &#91;Route(&quot;sync&quot;)]
    public IEnumerable&lt;string&gt; GetSync()
    {
        Response.Clear();
        Response.Headers.Add(&quot;Content-Disposition&quot;, &quot;attachment;filename=somenameasync.csv&quot;);
        Response.Headers.Add(&quot;Content-Transfer-Encoding&quot;, &quot;binary&quot;);
        return GetSyncContent();
    }

    private async IAsyncEnumerable&lt;string&gt; GetAsyncContent()
    {
        for (int i = 0; i &lt; 1000; i++)
        {
            await Task.Delay(1);
            yield return Guid.NewGuid().ToString().PadRight(1000000) + Environment.NewLine;
        }

    }

    private IEnumerable&lt;string&gt; GetSyncContent()
    {
        var strings = new List&lt;string&gt;();
        for (int i = 0; i &lt; 1000; i++)
        {
            strings.Add(Guid.NewGuid().ToString().PadRight(1000000) + Environment.NewLine);
        }

        return strings;
    }
}
</pre></div>


<p>The key part here is the signature of our method to generate the data &#8211; <strong>async IAsyncEnumerable</strong>.  I can now call yield return inside the loop and return one junk export at a time and stream it into the browser.  The memory is now staying around 100 MB for the same 1 GB file!  You have to of course use the same signature on the controller method to enable the magic.</p>



<p>Enjoy!</p>
]]></content:encoded>
					
					<wfw:commentRss>http://www.dotnetspeak.com/uncategorized/using-async-enumerable-to-save-memory/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Setting Up GitHub Actions</title>
		<link>http://www.dotnetspeak.com/net-core/setting-up-github-actions/</link>
					<comments>http://www.dotnetspeak.com/net-core/setting-up-github-actions/#respond</comments>
		
		<dc:creator><![CDATA[Sergey Barskiy]]></dc:creator>
		<pubDate>Sat, 15 Jan 2022 16:41:41 +0000</pubDate>
				<category><![CDATA[.Net Core]]></category>
		<category><![CDATA[GitHub]]></category>
		<category><![CDATA[.NET Core]]></category>
		<category><![CDATA[github;]]></category>
		<guid isPermaLink="false">http://www.dotnetspeak.com/?p=1476</guid>

					<description><![CDATA[I have some Open Source projects that I maintain in my “free” time.&#160; One of them is recurrence calculator – .NET library to computer recurrence date based on Outlook style rules: https://github.com/SergeyBarskiy/RecurrenceCalculator.&#160; I was adding support for .NET 6, and decided to invest into some automation.&#160; I wanted to setup two builds: one when I ...</p><p><a href="http://www.dotnetspeak.com/net-core/setting-up-github-actions/" class="more-link">Continue reading &#8216;Setting Up GitHub Actions&#8217; &#187;</a>]]></description>
										<content:encoded><![CDATA[<p>I have some Open Source projects that I maintain in my “free” time.&nbsp; One of them is recurrence calculator – .NET library to computer recurrence date based on Outlook style rules: <a title="https://github.com/SergeyBarskiy/RecurrenceCalculator" href="https://github.com/SergeyBarskiy/RecurrenceCalculator">https://github.com/SergeyBarskiy/RecurrenceCalculator</a>.&nbsp; I was adding support for .NET 6, and decided to invest into some automation.&nbsp; I wanted to setup two builds: one when I create pull request that builds and runs tests.&nbsp; Then other when I merge into master, which in addition will also push to nuget.org.&nbsp; I found a few articles and GitHub documentation, but nothing was specifying full flow.&nbsp; So, as I worked thought this task, I wanted to document entire action for the next person.</p>
<p>To create actions, you simply need to create yaml file for each one in your repo in .github/workflows folder</p>
<p>Action1 – build and test on pull request – <a href="https://github.com/SergeyBarskiy/RecurrenceCalculator/blob/master/.github/workflows/main.yml">main.yml</a></p>
<p>name: Build</p>
<p>on:<br />&nbsp;&nbsp; pull_request:<br />&nbsp;&nbsp;&nbsp;&nbsp; branches: [ master ]<br />&nbsp;&nbsp; workflow_dispatch:</p>
<p>jobs:<br />&nbsp;&nbsp; build:<br />&nbsp;&nbsp;&nbsp;&nbsp; env:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BUILD_CONFIG: &#8216;Release&#8217;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SOLUTION: &#8216;RecurrenceCalculator.sln&#8217;<br />&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp; runs-on: ubuntu-latest</p>
<p>&nbsp;&nbsp;&nbsp; steps:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8211; uses: actions/checkout@v2</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8211; name: Setup NuGet<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uses: NuGet/setup-nuget@v1.0.5</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8211; name: Restore dependencies<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; working-directory: ./RecurrenceCalculator<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; run: nuget restore $SOLUTION</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8211; name: Setup .NET<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uses: actions/setup-dotnet@v1<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; with:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dotnet-version: 6.0.*</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8211; name: Build<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; working-directory: ./RecurrenceCalculator<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; run: dotnet build $SOLUTION &#8211;configuration $BUILD_CONFIG &#8211;no-restore</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8211; name: Run tests<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; working-directory: ./RecurrenceCalculator<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; run: dotnet test $SOLUTION /p:Configuration=$BUILD_CONFIG &#8211;no-restore &#8211;no-build &#8211;verbosity normal</p>
<p>To explain a few things:</p>
<p>On section states to run on pull request against master branch.&nbsp; It will execute on that branch I want to merge to master.&nbsp; Plus on workflow dispatch, which means I can manually click a button to run it.&nbsp; Main step is build.&nbsp; I am setting up a couple of environmental variable to avoid repeating the same thing – build configuration and solution name.&nbsp; Then there are step to:</p>
<ul>
<li>Get source code from the branch – checkout action</li>
<li>Download and setup NuGet.&nbsp; I could use dotnet restore instead</li>
<li>Run nuget restore.&nbsp; Same comment – could use dotnet restore command instead</li>
<li>Download and setup .net exe and environment</li>
<li>Run build</li>
<li>Run tests</li>
</ul>
<p></p>
<p>Action 2 – build, test and publish to NuGet.org when merged into master <a href="https://github.com/SergeyBarskiy/RecurrenceCalculator/blob/master/.github/workflows/build-publish.yml">build-publish.yml</a></p>
<p>name: BuildAndPublish</p>
<p>on:<br />&nbsp;&nbsp; push:<br />&nbsp;&nbsp;&nbsp;&nbsp; branches: [ master ]<br />&nbsp;&nbsp;&nbsp;&nbsp; paths-ignore:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8211; &#8216;.github/**&#8217;<br />&nbsp;&nbsp; workflow_dispatch:</p>
<p>jobs:<br />&nbsp;&nbsp; build:<br />&nbsp;&nbsp;&nbsp;&nbsp; env:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BUILD_CONFIG: &#8216;Release&#8217;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SOLUTION: &#8216;RecurrenceCalculator.sln&#8217;<br />&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp; runs-on: ubuntu-latest</p>
<p>&nbsp;&nbsp;&nbsp; steps:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8211; uses: actions/checkout@v2</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8211; name: Setup NuGet<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uses: NuGet/setup-nuget@v1.0.5</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8211; name: Restore dependencies<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; working-directory: ./RecurrenceCalculator<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; run: nuget restore $SOLUTION</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8211; name: Setup .NET<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uses: actions/setup-dotnet@v1<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; with:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dotnet-version: 6.0.*</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8211; name: Build<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; working-directory: ./RecurrenceCalculator<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; run: dotnet build $SOLUTION &#8211;configuration $BUILD_CONFIG &#8211;no-restore</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8211; name: Run tests<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; working-directory: ./RecurrenceCalculator<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; run: dotnet test $SOLUTION /p:Configuration=$BUILD_CONFIG &#8211;no-restore &#8211;no-build &#8211;verbosity normal<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8211; name: Push to nuget<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; working-directory: ./RecurrenceCalculator<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; run: dotnet nuget push **/*.nupkg -s <a href="https://api.nuget.org/v3/index.json">https://api.nuget.org/v3/index.json</a> -k ${{secrets.NUGET_API_KEY}}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>The only additional step is to push to nuget.org.&nbsp; I did have to add a secret to the repo with the NuGet.org publish key and the secret’s name of NUGET_API_KEY</p>
<p>Enjoy</p>
]]></content:encoded>
					
					<wfw:commentRss>http://www.dotnetspeak.com/net-core/setting-up-github-actions/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Vote for a Cool Project</title>
		<link>http://www.dotnetspeak.com/community/vote-for-a-cool-project/</link>
					<comments>http://www.dotnetspeak.com/community/vote-for-a-cool-project/#respond</comments>
		
		<dc:creator><![CDATA[Sergey Barskiy]]></dc:creator>
		<pubDate>Tue, 01 Sep 2020 23:39:32 +0000</pubDate>
				<category><![CDATA[Community]]></category>
		<category><![CDATA[Design]]></category>
		<guid isPermaLink="false">http://www.dotnetspeak.com/?p=1468</guid>

					<description><![CDATA[My son is taking part in NATIONAL TEXAS INSTRUMENTS/NASA CODING CONTEST! If they advance, they get to visit NASA in Houston and present their project to NASA engineers at Johnson Space Center and Mission Control! VOTE FOR HIS DESIGN, THE ASTROBUTLER. Vote on each device you have!&#160; Go here to vote: https://education.ti.com/en/promotion/codescontest and click on ...</p><p><a href="http://www.dotnetspeak.com/community/vote-for-a-cool-project/" class="more-link">Continue reading &#8216;Vote for a Cool Project&#8217; &#187;</a>]]></description>
										<content:encoded><![CDATA[<p>My son is taking part in NATIONAL TEXAS INSTRUMENTS/NASA CODING CONTEST! If they advance, they get to visit NASA in Houston and present their project to NASA engineers at Johnson Space Center and Mission Control! VOTE FOR HIS DESIGN, THE ASTROBUTLER. Vote on each device you have!&nbsp; Go here to vote: <a href="https://education.ti.com/en/promotion/codescontest">https://education.ti.com/en/promotion/codescontest</a> and click on the project to vote!</p>
]]></content:encoded>
					
					<wfw:commentRss>http://www.dotnetspeak.com/community/vote-for-a-cool-project/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Materials I used to prepare for AWS Certification</title>
		<link>http://www.dotnetspeak.com/aws/materials-i-used-to-prepare-for-aws-certification/</link>
					<comments>http://www.dotnetspeak.com/aws/materials-i-used-to-prepare-for-aws-certification/#respond</comments>
		
		<dc:creator><![CDATA[Sergey Barskiy]]></dc:creator>
		<pubDate>Sun, 16 Aug 2020 20:17:54 +0000</pubDate>
				<category><![CDATA[AWS]]></category>
		<category><![CDATA[test]]></category>
		<guid isPermaLink="false">http://www.dotnetspeak.com/?p=1466</guid>

					<description><![CDATA[I have been studying for AWS Certified Solution Architect Associate for many months.&#160; I finally took the test this weekend.&#160; I wanted to document the preparation materials I used. I started with AWS Certification web site: https://aws.amazon.com/certification/certification-prep/ I read frequently asked questions page for all AWS services: https://aws.amazon.com/faqs/.&#160; I also specifically read all the white ...</p><p><a href="http://www.dotnetspeak.com/aws/materials-i-used-to-prepare-for-aws-certification/" class="more-link">Continue reading &#8216;Materials I used to prepare for AWS Certification&#8217; &#187;</a>]]></description>
										<content:encoded><![CDATA[<p>I have been studying for AWS Certified Solution Architect Associate for many months.&nbsp; I finally took the test this weekend.&nbsp; I wanted to document the preparation materials I used.</p>
<p>I started with AWS Certification web site: <a title="https://aws.amazon.com/certification/certification-prep/" href="https://aws.amazon.com/certification/certification-prep/">https://aws.amazon.com/certification/certification-prep/</a></p>
<p>I read frequently asked questions page for all AWS services: <a title="https://aws.amazon.com/faqs/" href="https://aws.amazon.com/faqs/">https://aws.amazon.com/faqs/</a>.&nbsp; I also specifically read all the white papers included in well architected framework: <a title="https://aws.amazon.com/architecture/well-architected/" href="https://aws.amazon.com/architecture/well-architected/">https://aws.amazon.com/architecture/well-architected/</a></p>
<p>I also read test preparation guide: <a title="https://d1.awsstatic.com/training-and-certification/docs-sa-assoc/AWS-Certified-Solutions-Architect-Associate_Exam-Guide.pdf" href="https://d1.awsstatic.com/training-and-certification/docs-sa-assoc/AWS-Certified-Solutions-Architect-Associate_Exam-Guide.pdf">https://d1.awsstatic.com/training-and-certification/docs-sa-assoc/AWS-Certified-Solutions-Architect-Associate_Exam-Guide.pdf</a> and read over sample questions: <a title="https://d1.awsstatic.com/training-and-certification/docs-sa-assoc/AWS-Certified-Solutions-Architect-Associate_Sample-Questions.pdf" href="https://d1.awsstatic.com/training-and-certification/docs-sa-assoc/AWS-Certified-Solutions-Architect-Associate_Sample-Questions.pdf">https://d1.awsstatic.com/training-and-certification/docs-sa-assoc/AWS-Certified-Solutions-Architect-Associate_Sample-Questions.pdf</a></p>
<p></p>
<p>Finally I took Udemy course: <a title="https://www.udemy.com/course/aws-certified-solutions-architect-associate-practice-exams-k/" href="https://www.udemy.com/course/aws-certified-solutions-architect-associate-practice-exams-k/">https://www.udemy.com/course/aws-certified-solutions-architect-associate-practice-exams-k/</a></p>
<p>I also when through sample questions book: <a title="https://www.amazon.com/Practice-Questions-2019-800-Guaranteed-ebook/dp/B07YG6NNW3" href="https://www.amazon.com/Practice-Questions-2019-800-Guaranteed-ebook/dp/B07YG6NNW3">https://www.amazon.com/Practice-Questions-2019-800-Guaranteed-ebook/dp/B07YG6NNW3</a></p>
<p>I hope this is helpful for some folks.</p>
]]></content:encoded>
					
					<wfw:commentRss>http://www.dotnetspeak.com/aws/materials-i-used-to-prepare-for-aws-certification/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Using ProxyKit to Simulate IIS Rewrite Rules</title>
		<link>http://www.dotnetspeak.com/asp-net-core/using-proxykit-to-simulate-iis-rewrite-rules/</link>
					<comments>http://www.dotnetspeak.com/asp-net-core/using-proxykit-to-simulate-iis-rewrite-rules/#respond</comments>
		
		<dc:creator><![CDATA[Sergey Barskiy]]></dc:creator>
		<pubDate>Mon, 02 Sep 2019 19:20:24 +0000</pubDate>
				<category><![CDATA[ASP.NET Core]]></category>
		<category><![CDATA[asp.net core]]></category>
		<guid isPermaLink="false">http://www.dotnetspeak.com/?p=1463</guid>

					<description><![CDATA[In many ASP.NET apps I worked on, I used reverse proxy in a number of situations.&#160; Typically I used IIS modules: Application Request Routing and URL Rewrite.&#160; You can install both inside IIS using Microsoft Web Platform Installer.&#160; In ASP.NET Core we cannot assume that the application is hosted on Windows inside IIS.&#160; As I ...</p><p><a href="http://www.dotnetspeak.com/asp-net-core/using-proxykit-to-simulate-iis-rewrite-rules/" class="more-link">Continue reading &#8216;Using ProxyKit to Simulate IIS Rewrite Rules&#8217; &#187;</a>]]></description>
										<content:encoded><![CDATA[<p>In many ASP.NET apps I worked on, I used reverse proxy in a number of situations.&nbsp; Typically I used IIS modules: Application Request Routing and URL Rewrite.&nbsp; You can install both inside IIS using Microsoft Web Platform Installer.&nbsp; In ASP.NET Core we cannot assume that the application is hosted on Windows inside IIS.&nbsp; As I looked around for the replacement, I found this open source project: <a href="https://github.com/damianh/ProxyKit" target="_blank" rel="noopener noreferrer">ProxyKit</a>.&nbsp; I created&nbsp; small demo to verify that it works.&nbsp; I picked a simple use case.&nbsp; When I see a specific fragment inside the request URL, I would to create new URL by using predefined server and its path plus whatever follows the segment in question in the original URL. For example, I if I see request <a href="http://localhost:5001/my/site">http://localhost:5001/my/site</a> and my fragment is “my” and new URL is <a href="http://localhost:5002/site">http://localhost:5002/site</a>.</p>
<p>So, first step is to define our rules.&nbsp; I am just going to dream up the the configuration:</p>
<div class="wlWriterEditableSmartContent" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:e7f5e4bf-00b0-4d39-85b9-f347feaacbbb" style="margin: 0px; padding: 0px; float: none; display: inline;">
<pre style=white-space:normal>
<pre class="brush: jscript; pad-line-numbers: true; title: ; notranslate">
{
  &quot;Logging&quot;: {
    &quot;LogLevel&quot;: {
      &quot;Default&quot;: &quot;Information&quot;,
      &quot;Microsoft&quot;: &quot;Warning&quot;,
      &quot;Microsoft.Hosting.Lifetime&quot;: &quot;Information&quot;
    }
  },
  &quot;AllowedHosts&quot;: &quot;*&quot;,
  &quot;proxy&quot;: {
    &quot;path&quot;: &quot;/weather/v1/my/&quot;,
    &quot;redirectTo&quot;: &quot;http://localhost:5002/&quot;
  }
}
</pre>
</div>
<p>My config is under proxy section.&nbsp; Now I am going to use <a href="https://github.com/damianh/ProxyKit/tree/master/src/Recipes" target="_blank" rel="noopener noreferrer">recipes</a> to create my code.&nbsp; Mainly I am basing this on conditional recipe.</p>
<div class="wlWriterEditableSmartContent" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:adc1f2ee-45b6-464e-aa4a-df1dc5dd0dcf" style="margin: 0px; padding: 0px; float: none; display: inline;">
<pre style=white-space:normal>
<pre class="brush: csharp; title: ; notranslate">
using System;
using System.Text.RegularExpressions;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using ProxyKit;

namespace Site1
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
            services.AddProxy();
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            var testPath = Configuration[&quot;proxy:path&quot;];
            var redirectTo = Configuration[&quot;proxy:redirectTo&quot;];
            app.UseWhen(context =&gt;
            {
                return Regex.IsMatch(context.Request.Path.ToString(), testPath, RegexOptions.IgnoreCase);
            },
            app =&gt;
            {
                app.RunProxy(context =&gt;
                {
                    var finalUrl = Regex.Replace(context.Request.Path.ToString().ToLower(), testPath, redirectTo, RegexOptions.IgnoreCase);
                    var finalContext = context.ForwardTo(finalUrl);
                    finalContext.UpstreamRequest.RequestUri = new Uri(finalUrl);

                    return finalContext
                        .CopyXForwardedHeaders()
                        .AddXForwardedHeaders()
                        .Send();
                });
            });

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseRouting();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =&gt;
            {
                endpoints.MapControllers();
            });
        }
    }
}
</pre>
</div>
<p>If you look at the UseWhen line, I am testing the request for the initial path in my Rewrite rule.&nbsp; I am using regular expressions for performance reasons.&nbsp; Then, when condition is met, I am creating new URL based on my requirements.&nbsp; I am replacing parts of the URL with the replacement.&nbsp; I am using ProxyKit’s ForwardTo method, but I also have to replace the URL in the forwarded context’s Upstream Request.&nbsp; I am also adding standard forward headers.&nbsp; So far I love this library, and wanted to share my excitement.&nbsp; Thanks, <a href="https://github.com/damianh" target="_blank" rel="noopener noreferrer">Damian</a> for your work.</p>
<p>Enjoy.</p>
]]></content:encoded>
					
					<wfw:commentRss>http://www.dotnetspeak.com/asp-net-core/using-proxykit-to-simulate-iis-rewrite-rules/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Creating Schedule Driven Windows Service in .NET Core 3.0</title>
		<link>http://www.dotnetspeak.com/net-core/creating-schedule-driven-windows-service-in-net-core-3-0/</link>
					<comments>http://www.dotnetspeak.com/net-core/creating-schedule-driven-windows-service-in-net-core-3-0/#respond</comments>
		
		<dc:creator><![CDATA[Sergey Barskiy]]></dc:creator>
		<pubDate>Sun, 01 Sep 2019 18:43:12 +0000</pubDate>
				<category><![CDATA[.Net Core]]></category>
		<category><![CDATA[Windows Service]]></category>
		<category><![CDATA[.NET Core]]></category>
		<category><![CDATA[Quartz]]></category>
		<category><![CDATA[Windows]]></category>
		<guid isPermaLink="false">http://www.dotnetspeak.com/?p=1460</guid>

					<description><![CDATA[The upcoming version of .NET Core, 3.0, will have native support for Windows and Linux Services.&#160; On Windows the services will rely on standard Windows features.&#160; On Linux it will rely on Systemd.&#160; One of the most common use of windows services in to run background tasks based on a schedule.&#160; One of the most ...</p><p><a href="http://www.dotnetspeak.com/net-core/creating-schedule-driven-windows-service-in-net-core-3-0/" class="more-link">Continue reading &#8216;Creating Schedule Driven Windows Service in .NET Core 3.0&#8217; &#187;</a>]]></description>
										<content:encoded><![CDATA[<p>The upcoming version of <a href="https://dotnet.microsoft.com/download/dotnet-core" target="_blank" rel="noopener noreferrer">.NET Core</a>, 3.0, will have native support for Windows and Linux Services.&nbsp; On Windows the services will rely on standard Windows features.&nbsp; On Linux it will rely on <a href="https://www.linux.com/tutorials/understanding-and-using-systemd/" target="_blank" rel="noopener noreferrer">Systemd</a>.&nbsp; One of the most common use of windows services in to run background tasks based on a schedule.&nbsp; One of the most popular frameworks for scheduling in <a href="https://www.quartz-scheduler.net" target="_blank" rel="noopener noreferrer">Quartz.net</a>.&nbsp; In this quick post I will demonstrate now to achieve this task on Windows.&nbsp; Let’s go step by step.</p>
<p>As <font color="#ff0000"><em>step 1</em></font>, you will need to <a href="https://visualstudio.microsoft.com/vs/preview/" target="_blank" rel="noopener noreferrer">download</a> and install Visual Studio preview 16.3 that includes support for .NET Core 3.0 and C#8.&nbsp; Of course, the Studio may be released by the time you are reading this, so you do not need to use preview in this case, use main download <a href="https://visualstudio.microsoft.com/" target="_blank" rel="noopener noreferrer">channel</a>.</p>
<p>In <font color="#ff0000"><strong><em>step 2</em></strong></font>, run Visual Studio, select Create New Project, and pick template called Worker Service.&nbsp; This will stub out the project for you with two files.&nbsp; Program.cs is your entry point.&nbsp; Worker.cs is the actual service worker.</p>
<p>In <font color="#ff0000"><strong><em>step 3</em></strong></font>, we need to enable Windows service infrastructure by calling UseWindowsServices extension method.</p>
<div class="wlWriterEditableSmartContent" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:16392233-e07f-49e9-bf2d-16dd71e41807" style="margin: 0px; padding: 0px; float: none; display: inline;">
<pre style=white-space:normal>
<pre class="brush: csharp; title: ; notranslate">
        public static IHostBuilder CreateHostBuilder(string[] args) =&gt;
            Host.CreateDefaultBuilder(args)
            .UseWindowsService()
            .ConfigureServices((hostContext, services) =&gt;
            {
                services.AddHostedService&lt;Worker&gt;();
            });
</pre>
</div>
<p>To use Quartz we need to install the NuGet package called Quartz.&nbsp; </p>
<p>In the next step we need to create a couple of Jobs.</p>
<div class="wlWriterEditableSmartContent" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:abdb0b7f-da57-435c-b09c-1a9fa3712b17" style="margin: 0px; padding: 0px; float: none; display: inline;">
<pre style=white-space:normal>
<pre class="brush: csharp; title: ; notranslate">
    public class Job1 : IJob
    {
        public async Task Execute(IJobExecutionContext context)
        {
            await File.AppendAllLinesAsync(@&quot;c:\temp\job1.txt&quot;, new[] { DateTime.Now.ToLongTimeString() });
        }
    }
</pre>
</div>
<div class="wlWriterEditableSmartContent" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:7527a0f2-2106-45b6-a3be-b20548a0379b" style="margin: 0px; padding: 0px; float: none; display: inline;">
<pre style=white-space:normal>
<pre class="brush: csharp; title: ; notranslate">
    public class Job2 : IJob
    {
        public async Task Execute(IJobExecutionContext context)
        {
            await File.AppendAllLinesAsync(@&quot;c:\temp\job2.txt&quot;, new[] { DateTime.Now.ToLongTimeString() });
        }
    }
</pre>
</div>
<p>The jobs just update text file, they are demo jobs after all, in c:\temp folder.&nbsp; You need to create this folder if it does not exist.</p>
<p>In the next step we need to create schedule and schedule the jobs.&nbsp; The final Worker class looks as follows.</p>
<div class="wlWriterEditableSmartContent" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:64797807-c1eb-4df1-9dc0-cc0d3a185ba9" style="margin: 0px; padding: 0px; float: none; display: inline;">
<pre style=white-space:normal>
<pre class="brush: csharp; title: ; notranslate">
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Quartz;
using Quartz.Impl;

namespace WorkerService1
{
    public class Worker : BackgroundService
    {
        private readonly ILogger&lt;Worker&gt; _logger;
        private StdSchedulerFactory _schedulerFactory;
        private CancellationToken _stopppingToken;
        private IScheduler _scheduler;

        public Worker(ILogger&lt;Worker&gt; logger)
        {
            _logger = logger;
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            await StartJobs();
            _stopppingToken = stoppingToken;
            while (!stoppingToken.IsCancellationRequested)
            {
                await Task.Delay(1000, stoppingToken);
            }
            await _scheduler.Shutdown();
        }

        protected async Task StartJobs()
        {
            _schedulerFactory = new StdSchedulerFactory();

            _scheduler = await _schedulerFactory.GetScheduler();
            await _scheduler.Start();

            IJobDetail job1 = JobBuilder.Create&lt;Job1&gt;()
                .WithIdentity(&quot;job1&quot;, &quot;gtoup&quot;)
                .Build();

            ITrigger trigger1 = TriggerBuilder.Create()
                .WithIdentity(&quot;trigger_10_sec&quot;, &quot;group&quot;)
                .StartNow()
                .WithSimpleSchedule(x =&gt; x
                    .WithIntervalInSeconds(10)
                    .RepeatForever())
            .Build();


            IJobDetail job2 = JobBuilder.Create&lt;Job2&gt;()
               .WithIdentity(&quot;job2&quot;, &quot;group&quot;)
               .Build();

            ITrigger trigger2 = TriggerBuilder.Create()
                .WithIdentity(&quot;trigger_20_sec&quot;, &quot;group&quot;)
                .StartNow()
                .WithSimpleSchedule(x =&gt; x
                    .WithIntervalInSeconds(20)
                    .RepeatForever())
            .Build();


            await _scheduler.ScheduleJob(job1, trigger1, _stopppingToken);
            await _scheduler.ScheduleJob(job2, trigger2, _stopppingToken);
        }
    }
}
</pre>
</div>
<p>Now we just run the project and observe everything working.&nbsp; Now we need to confirm that we can install and run our code as Windows Service.&nbsp; </p>
<p>In this final step, we need to install the service by typing the following on the command prompt to create the service:</p>
<p><strong>sc create &#8220;service1&#8243; binPath=&#8221;C:\Users\serge.000\Source\Repos\WorkerService1\WorkerService1\bin\Debug\netcoreapp3.0\WorkerService1.exe&#8221;</strong></p>
<p>To start the service just type the following and hit Enter</p>
<p><strong>sc start service1</strong></p>
<p>We should now see our files being updated in c:\temp folder at different intervals, base on the schedules we setup for each job.&nbsp; When your testing is done, type “<strong><em>sc stop service1</em></strong>” to stop the service.&nbsp; Then type “<strong><em>sc delete service1</em></strong>” to remove the service from your machine.&nbsp; </p>
<p>Enjoy.</p>
]]></content:encoded>
					
					<wfw:commentRss>http://www.dotnetspeak.com/net-core/creating-schedule-driven-windows-service-in-net-core-3-0/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Distributed Cache, Redis and .NET Core</title>
		<link>http://www.dotnetspeak.com/asp-net-core/distributed-cache-redis-and-net-core/</link>
					<comments>http://www.dotnetspeak.com/asp-net-core/distributed-cache-redis-and-net-core/#comments</comments>
		
		<dc:creator><![CDATA[Sergey Barskiy]]></dc:creator>
		<pubDate>Sun, 25 Aug 2019 19:47:24 +0000</pubDate>
				<category><![CDATA[.Net Core]]></category>
		<category><![CDATA[ASP.NET Core]]></category>
		<category><![CDATA[Cache]]></category>
		<category><![CDATA[.NET Core]]></category>
		<category><![CDATA[asp.net core]]></category>
		<category><![CDATA[cache]]></category>
		<category><![CDATA[distributed cache]]></category>
		<guid isPermaLink="false">http://www.dotnetspeak.com/?p=1458</guid>

					<description><![CDATA[In many apps there is a need to have distributed cache.&#160; For years now, adopting distributed cache on Windows has been a challenge.&#160; Most popular product, Redis, is no longer supported on Windows platform.&#160; The easiest way to get it going on Windows today is Docker for Windows in my opinion.&#160; To do so, first ...</p><p><a href="http://www.dotnetspeak.com/asp-net-core/distributed-cache-redis-and-net-core/" class="more-link">Continue reading &#8216;Distributed Cache, Redis and .NET Core&#8217; &#187;</a>]]></description>
										<content:encoded><![CDATA[<p>In many apps there is a need to have <a href="https://en.wikipedia.org/wiki/Distributed_cache" target="_blank" rel="noopener noreferrer">distributed cache</a>.&nbsp; For years now, adopting distributed cache on Windows has been a challenge.&nbsp; Most popular product, <a href="https://redislabs.com/" target="_blank" rel="noopener noreferrer">Redis</a>, is no longer supported on Windows platform.&nbsp; The easiest way to get it going on Windows today is Docker for Windows in my opinion.&nbsp; To do so, first you have to install <a href="https://docs.docker.com/docker-for-windows/" target="_blank" rel="noopener noreferrer">Docker for Windows</a>.&nbsp; I am a fan of graphical user interfaces, so I would also recommend installing <a href="https://kitematic.com/" target="_blank" rel="noopener noreferrer">Kitematic</a>.&nbsp; Once that is done, run Kitematic, click New and in search box type Redis.&nbsp; In search results pick Redis (Redis:latest) and click Create.&nbsp; Now just wait a bit while you are downloading and isntalling Redis.&nbsp; Eventually, you will see in Kitematic that Redis is running.&nbsp; Now you can test Redis.&nbsp; Open command prompt, I use <a href="https://www.microsoft.com/en-us/p/windows-terminal-preview/9n0dx20hk701" target="_blank" rel="noopener noreferrer">Terminal for Windows</a>.&nbsp; You can use PowerShell or Command Prompt, either one.&nbsp; </p>
<p>Type the following and hit Enter</p>
<p><em><strong>docker exec -it redis sh</strong></em></p>
<p>At the next prompt type the following and hit Enter</p>
<p><strong><em>redis-cli</em></strong></p>
<p>Now type the following and hit Enter</p>
<p><font color="#000000"><strong>set name John</strong></font></p>
<p>You should see Ok.&nbsp; Now type the following and hit Enter.</p>
<p><strong>get name</strong></p>
<p>You should see John, meaning that you were successful in storing and retrieving a cache entry with the key of <strong>name</strong> and value of <strong>John</strong>.</p>
<p>Now let’s create new .NET Core Console app.&nbsp; Run Visual Studio, create new project, pick .NET Core Console App.&nbsp; Add new NuGet package of Microsoft.Extensions.Caching.Redis.Core.&nbsp; For testing reason I am just going to create options class.</p>
<div class="wlWriterEditableSmartContent" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:ad75c9da-5911-4f70-9698-bdd2a57f7664" style="margin: 0px; padding: 0px; float: none; display: inline;">
<pre style=white-space:normal>
<pre class="brush: csharp; pad-line-numbers: true; title: ; notranslate">
    public class MyRedisOptions : IOptions&amp;lt;RedisCacheOptions&amp;gt;
    {
        public RedisCacheOptions Value =&amp;gt; new RedisCacheOptions
        {
            Configuration = &amp;quot;127.0.0.1:32768&amp;quot;,
            InstanceName = &amp;quot;serge&amp;quot;
        };
    }
</pre>
</div>
<p></p>
<p>The main thing you see is the port number.&nbsp; You can get that from Kitematic.&nbsp; If you click on Redis image, under IP and ports you will see Access Url, this is what we need.&nbsp; I would like to store a instance of a class, so I am going to create a person class.</p>
<div class="wlWriterEditableSmartContent" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:f5260b30-558d-499a-81c6-fec37324c5f8" style="margin: 0px; padding: 0px; float: none; display: inline;">
<pre style=white-space:normal>
<pre class="brush: csharp; title: ; notranslate">
    [Serializable]
    public class Person
    {
        public string Name { get; set; }
        public Person Parent { get; set; }
    }
</pre>
</div>
<p>You will notices that I added Serializable attribute.&nbsp; This comes for requirement of <a href="https://docs.microsoft.com/en-us/aspnet/core/performance/caching/distributed?view=aspnetcore-2.2" target="_blank" rel="noopener noreferrer">IDistributedCache</a> interface.&nbsp; it only operations on byte arrays.&nbsp; I am going to lean on <a href="https://docs.microsoft.com/en-us/dotnet/api/system.runtime.serialization.formatters.binary.binaryformatter?view=netcore-2.2" target="_blank" rel="noopener noreferrer">BinaryFormatter</a> class, new in .NET Code 2.1 to serialize an object into a byte array.&nbsp; I am going to create a little extensions class for that that I can reuse everywhere.</p>
<div class="wlWriterEditableSmartContent" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:44b45626-de06-4ccd-a512-57198466a485" style="margin: 0px; padding: 0px; float: none; display: inline;">
<pre style=white-space:normal>
<pre class="brush: csharp; title: ; notranslate">
    public static class IDistributedCacheExtensions
    {
        public static async Task SetAsync&amp;lt;T&amp;gt;(this IDistributedCache cache, string key, T value, DistributedCacheEntryOptions options)
            where T : class, new()
        {
            using (var stream = new MemoryStream())
            {
                new BinaryFormatter().Serialize(stream, value);
                await cache.SetAsync(key, stream.ToArray(), options);
            }
        }

        public static async Task&amp;lt;T&amp;gt; GetAsync&amp;lt;T&amp;gt;(this IDistributedCache cache, string key)
            where T : class, new()
        {
            var data = await cache.GetAsync(key);
            using (var stream = new MemoryStream(data))
            {
                {
                    return (T)new BinaryFormatter().Deserialize(stream);
                }
            }
        }


        public static async Task SetAsync(this IDistributedCache cache, string key, string value, DistributedCacheEntryOptions options)
        {
            await cache.SetAsync(key, Encoding.UTF8.GetBytes(value), options);
        }

        public static async Task&amp;lt;string&amp;gt; GetAsync(this IDistributedCache cache, string key)
        {

            var data = await cache.GetAsync(key);
            if(data != null)
            {
                return Encoding.UTF8.GetString(data);
            }
            return null;
        }
    }
</pre>
</div>
<p>I am ready for the final test in my console app.</p>
<div class="wlWriterEditableSmartContent" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:d9092df7-9211-4508-afef-fe231e04d2ab" style="margin: 0px; padding: 0px; float: none; display: inline;">
<pre style=white-space:normal>
<pre class="brush: csharp; title: ; notranslate">
    class Program
    {
        public static async Task Main(string[] args)
        {
            RedisCache cache = new RedisCache(new MyRedisOptions());
            var person = new Person
            {
                Name = &amp;quot;Sergey&amp;quot;,
                Parent = new Person
                {
                    Name = &amp;quot;John&amp;quot;
                }
            };
            await cache.SetAsync(&amp;quot;sergey&amp;quot;, person, new DistributedCacheEntryOptions ());

            var p = await cache.GetAsync&amp;lt;Person&amp;gt;(&amp;quot;sergey&amp;quot;);
            Console.WriteLine(p.Name + &amp;quot; &amp;quot; + p.Parent.Name);

            await cache.SetAsync(&amp;quot;random&amp;quot;, &amp;quot;some value&amp;quot;, new DistributedCacheEntryOptions());
            Console.ReadKey();
        }
    }
</pre>
</div>
<p>As you can see I am creating an instance of RedisCache, new instance of a Person class, then just set and retrieve the value of Person and some random string.</p>
<p>A few of thoughts in conclusion.</p>
<ul>
<li>Did you notice that I used async main?&nbsp; Console apps now support async entry point!</li>
<li>In normal asp.net core app I would not use Redis options directly, instead I would use <a href="https://docs.microsoft.com/en-us/aspnet/core/performance/caching/distributed?view=aspnetcore-2.2" target="_blank" rel="noopener noreferrer">methods</a> available in Microsoft.Extensions.Caching.Redis.Core to inject and configure Redis as distributed cache.</li>
<li>Now anytime I need distributed cache, I would inject IDistributedCache and set or retrieve the data.</li>
<li>I can also use Json.Net to serialize or deserialize object.</li>
</ul>
<p></p>
<p>Thanks and enjoy.</p>
]]></content:encoded>
					
					<wfw:commentRss>http://www.dotnetspeak.com/asp-net-core/distributed-cache-redis-and-net-core/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Controlling Scrolling with @Angular/flex-layout</title>
		<link>http://www.dotnetspeak.com/angular/controlling-scrolling-with-angularflex-layout/</link>
					<comments>http://www.dotnetspeak.com/angular/controlling-scrolling-with-angularflex-layout/#comments</comments>
		
		<dc:creator><![CDATA[Sergey Barskiy]]></dc:creator>
		<pubDate>Sat, 16 Mar 2019 18:04:52 +0000</pubDate>
				<category><![CDATA[Angular]]></category>
		<category><![CDATA[angualr2]]></category>
		<category><![CDATA[flex]]></category>
		<guid isPermaLink="false">http://www.dotnetspeak.com/?p=1451</guid>

					<description><![CDATA[Flex-layout library written by Angular team can be used to layout our web applications written in @Angular.&#160; One of the issues that we had to persistently deal with is to control scrolling in various parts of the screen independently.&#160; We can always let browser control the vertical scrolling.&#160; However, this becomes a problem with more ...</p><p><a href="http://www.dotnetspeak.com/angular/controlling-scrolling-with-angularflex-layout/" class="more-link">Continue reading &#8216;Controlling Scrolling with @Angular/flex-layout&#8217; &#187;</a>]]></description>
										<content:encoded><![CDATA[<p><a href="https://github.com/angular/flex-layout" target="_blank">Flex-layout</a> library written by Angular team can be used to layout our web applications written in @<a href="https://angular.io/guide/quickstart" target="_blank">Angular</a>.&nbsp; One of the issues that we had to persistently deal with is to control scrolling in various parts of the screen independently.&nbsp; We can always let browser control the vertical scrolling.&nbsp; However, this becomes a problem with more complex layouts, where for example, you want to have to columns, each one with independent scrolling.&nbsp; Another example would be to let left column be fixed, and write to be scrollable.&nbsp; If you let browser control scrolling, you will see that left side, albeit fixed, will show unusable space underneath.&nbsp; Here is an example that looks Ok to begin with, but looks strange when you scroll the left side.</p>
<p></p>
<p><a href="https://i0.wp.com/www.dotnetspeak.com/wp-content/uploads/2019/03/image.png"><img loading="lazy" width="244" height="153" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://i0.wp.com/www.dotnetspeak.com/wp-content/uploads/2019/03/image_thumb.png?resize=244%2C153" border="0" data-recalc-dims="1"></a></p>
<p></p>
<p><a href="https://i1.wp.com/www.dotnetspeak.com/wp-content/uploads/2019/03/image-1.png"><img loading="lazy" width="244" height="157" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://i1.wp.com/www.dotnetspeak.com/wp-content/uploads/2019/03/image_thumb-1.png?resize=244%2C157" border="0" data-recalc-dims="1"></a></p>
<p>I wanted to create a clean prescriptive solution for independent vertical scrolling in multiple components.&nbsp; To demonstrate I will re-create the layout above with a few components.</p>
<ul>
<li>Root component that is created automatically when you scaffold new app with <a href="https://github.com/angular/angular-cli" target="_blank">Angular CLI</a>.</li>
<li>Left side component, called BlueComponent</li>
<li>Write side wrapper component, called YellowComponent</li>
<li>Small component that will be in the first row inside yellow, called RedComponent</li>
<li>Component that will host a list, called GreenComponent</li>
<li>Component which be a row inside green component, called ScrollableOrangeComponent</li>
</ul>
<p>What I want is for yellow and blow occupy 50% of width of the visible screen without scrolling.&nbsp; I also want the content of the green component to scroll independently.</p>
<p>Here is how it looks when all rows inside green are visible due to browser size.</p>
<p><a href="https://i0.wp.com/www.dotnetspeak.com/wp-content/uploads/2019/03/image-2.png"><img loading="lazy" width="244" height="244" title="image" style="display: inline; background-image: none;" alt="image" src="https://i2.wp.com/www.dotnetspeak.com/wp-content/uploads/2019/03/image_thumb-2.png?resize=244%2C244" border="0" data-recalc-dims="1"></a></p>
<p>Here is how it looks when green does not have enough height to accommodate all the instance of orange component</p>
<p><a href="https://i1.wp.com/www.dotnetspeak.com/wp-content/uploads/2019/03/image-3.png"><img loading="lazy" width="244" height="209" title="image" style="margin: 0px; display: inline; background-image: none;" alt="image" src="https://i1.wp.com/www.dotnetspeak.com/wp-content/uploads/2019/03/image_thumb-3.png?resize=244%2C209" border="0" data-recalc-dims="1"></a></p>
<p>I created components with borders so that I can tell where it ends. In this case I achieved my goal.&nbsp; How is this done?&nbsp; You have to follow a few steps.</p>
<p><strong>1. We have to constraint the browser window vertically to ensure there are no scrollbars in the browser, as you may end up with multiple vertical scrollbars in this case.</strong></p>
<p>This can be done by setting a little bit of css applied to the body element in the shared root CSS file included in Angular template project.&nbsp; This file is called styles.css. I am going to use vertical size units called <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/length" target="_blank">vh</a>.&nbsp; These are vertical height percentage unit.&nbsp; If we set that to 100, this would occupy all available vertical space.&nbsp; We also want to reset margins to ensure that they are 0 and occupy no space.</p>
<div class="wlWriterEditableSmartContent" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:f0bb5131-1f74-473d-a857-76e34e674089" style="margin: 0px; padding: 0px; float: none; display: inline;">
<pre style=white-space:normal>
<pre class="brush: css; pad-line-numbers: true; title: ; notranslate">
body {
    height: 100vh;
    background-color: bisque;
    margin: 0;
}
</pre>
</div>
<p>I set background color to be able to see the body.&nbsp; In my case I do not see any, which is the idea.</p>
<p><font color="#000000"><strong>2.&nbsp; Now we have to setup root component to also be constrained vertically.</strong></font></p>
<p>In order to do this, we have to use row layout from flex-layout (or flexbox) library.&nbsp; I want to have to 50% columns, one for blue, one for yellow.</p>
<p>&lt;div fxFlexFill fxLayoutAlign=&#8221;start stretch&#8221; fxLayout=&#8221;row&#8221; class=&#8221;root&#8221;&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;app-blue fxFlex=&#8221;50&#8243; fxFlexFill&gt;&lt;/app-blue&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;app-yellow fxFlex&gt;&lt;/app-yellow&gt;</p>
<p>&lt;/div&gt;</p>
<p>Let’s walk through this if you have not use flex-layout library before.&nbsp; FxFlexFill stretches out the content to occupy all available space, aka 100% of width and height.&nbsp; fxLayout set to row, making sure that our content will be arranged as a number of columns.&nbsp; In our case we have two compoentns: blue and yellow.&nbsp; Each one is set to 50% via fxFlex=”50”.&nbsp; We are using fxFlexFill on blue as well.&nbsp; We are using additional root class, but just to set the border so that we can see our root component.</p>
<p>Blue component is very simple, just a title.</p>
<p>&lt;div class=&#8221;blue&#8221; fxLayout=&#8221;row&#8221; fxlayoutAlign=&#8221;start stretch&#8221; fxFlexFill&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;div fxFlex&gt;Blue&lt;/div&gt;</p>
<p>&lt;/div&gt;</p>
<p>Again we are making sure it stretches the content with fxFlexFill.&nbsp; It’s layout is not relevant for us.</p>
<p><strong>3.&nbsp; Now we need to setup component on the right hand side with two components inside arranged in rows.</strong></p>
<p>&lt;div class=&#8221;yellow&#8221; fxLayout=&#8221;column&#8221; fxlayoutAlign=&#8221;start stretch&#8221; fxFlexFill&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;div fxFlex=&#8221;none&#8221;&gt;Yellow&lt;/div&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;app-red fxFlex=&#8221;none&#8221;&gt;&lt;/app-red&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;app-green fxFlex&gt;&lt;/app-green&gt;</p>
<p>&lt;/div&gt;</p>
<p>What we have here is fxLayout set to column in order to arrange the inner components in rows.&nbsp; In the first row we have just the title.&nbsp; We are setting it;s fxFlex to none in order to opt out of flexbox layout and let the component size itself.&nbsp; Red component in the next row, also opting out of any resizing.&nbsp; Finally, our green component is set to fxFlex without a value, which means occupy all available space, in this case vertical space of the last row,</p>
<p><strong>4.&nbsp; Now we need to setup our next component to accommodate scrollable content when necessary.</strong></p>
<p>&lt;div class=&#8221;green&#8221; fxLayout=&#8221;column&#8221; fxlayoutAlign=&#8221;start stretch&#8221;&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;div fxFlex&gt;Green&lt;/div&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;app-scrollable-orange [title]=&#8221;item&#8221; *ngFor=&#8221;let item of items&#8221;&gt;&lt;/app-scrollable-orange&gt;</p>
<p>&lt;/div&gt;</p>
<p>We layout this component’s contents in rows, using fxLayout set to column.&nbsp; We set layout align to start stretch, where start means in the direction of the layout, horizontally in this case.&nbsp; Then we want to occupy all available space in perpendicular direction, vertically in this case.&nbsp; Then we are creating some number of scrollable components, using ngFor.</p>
<div class="wlWriterEditableSmartContent" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:12088c9b-38d3-49d5-8307-4bffee4fda24" style="margin: 0px; padding: 0px; float: none; display: inline;">
<pre style=white-space:normal>
<pre class="brush: jscript; title: ; notranslate">
import { Component, OnInit } from &amp;#39;@angular/core&amp;#39;;

@Component({
  selector: &amp;#39;app-green&amp;#39;,
  templateUrl: &amp;#39;./green.component.html&amp;#39;,
  styleUrls: [&amp;#39;./green.component.css&amp;#39;]
})
export class GreenComponent implements OnInit {
  items: number[] = [];
  constructor() {}

  ngOnInit() {
    for (let i = 1; i &amp;lt;= 40; i++) {
      this.items.push(i);
    }
  }
}
</pre>
</div>
<p>We do that in the onInit method.&nbsp; We also need to enable scrolling in this component in its css file.</p>
<div class="wlWriterEditableSmartContent" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:0cca6f62-4f14-4891-b3b9-5bba69e98b84" style="margin: 0px; padding: 0px; float: none; display: inline;">
<pre style=white-space:normal>
<pre class="brush: css; title: ; notranslate">
.green {
  background: green;
  color: white;
  border: 5px bisque solid;
}
:host {
  overflow-y: auto;
}
</pre>
</div>
<p>We do two things here.&nbsp; We set vertical overflow to automatic on the :host.&nbsp; When angular creates components, it will create a component html tag, in our case aap-green, as this is what we have in our yellow component, then it will put the content of the green’s template inside of it.&nbsp; We want to make sure the outer element (app-green) is scrollable.&nbsp; Inside the css this is visible as :host.&nbsp; The rest if css is not relevant, and just controls the colors.</p>
<p>Scrollable orange component is also not relevant for the layout, but for the sake of completeness, here is its source:</p>
<div class="wlWriterEditableSmartContent" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:21b23941-f91d-49d3-a64f-4138383c1d60" style="margin: 0px; padding: 0px; float: none; display: inline;">
<pre style=white-space:normal>
<pre class="brush: jscript; title: ; notranslate">
import { Component, OnInit, Input } from &amp;#39;@angular/core&amp;#39;;

@Component({
  selector: &amp;#39;app-scrollable-orange&amp;#39;,
  templateUrl: &amp;#39;./scrollable-orange.component.html&amp;#39;,
  styleUrls: [&amp;#39;./scrollable-orange.component.css&amp;#39;]
})
export class ScrollableOrangeComponent implements OnInit {

  @Input() title?: string = &amp;quot;1&amp;quot;;

  constructor() { }


  ngOnInit() {
  }

}
</pre>
</div>
<p>It’s template is also simple:</p>
<p>&lt;div class=&#8221;orange&#8221;&gt;Orange {{ title }}&lt;/div&gt;</p>
<p>That is it.&nbsp; So, to summarize, we have to constrain the body and root component vertically.&nbsp; Then we need to allow our component with scrollable content to occupy all available vertical space inside its parent and show scrollbar when the content is too large.&nbsp; You can do something similar for horizontal scrolling, but this is far less common.</p>
<p>You can download the sample project <a href="/Downloads/scrolling.zip" target="_blank">here</a>.</p>
<p>Enjoy.</p>
]]></content:encoded>
					
					<wfw:commentRss>http://www.dotnetspeak.com/angular/controlling-scrolling-with-angularflex-layout/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>IIS Log Parser</title>
		<link>http://www.dotnetspeak.com/uncategorized/iis-log-parser/</link>
					<comments>http://www.dotnetspeak.com/uncategorized/iis-log-parser/#respond</comments>
		
		<dc:creator><![CDATA[Sergey Barskiy]]></dc:creator>
		<pubDate>Tue, 11 Dec 2018 22:47:54 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">http://www.dotnetspeak.com/?p=1439</guid>

					<description><![CDATA[I was troubleshooting performance issues today and needed to analyze IIS logs to see which requests are slow.  In the past I was able to use just Notepad to do that for small logs.  Today&#8217;s log was 172 MB in size, and I had some serious issues, even with Notepad++ trying to make sense of ...</p><p><a href="http://www.dotnetspeak.com/uncategorized/iis-log-parser/" class="more-link">Continue reading &#8216;IIS Log Parser&#8217; &#187;</a>]]></description>
										<content:encoded><![CDATA[<p>I was troubleshooting performance issues today and needed to analyze IIS logs to see which requests are slow.  In the past I was able to use just Notepad to do that for small logs.  Today&#8217;s log was 172 MB in size, and I had some serious issues, even with Notepad++ trying to make sense of the data.  I looked around and found this great tool: Log Parser Studio.</p>
<p>You can download it from Tech Net Marketplace: <a href="https://gallery.technet.microsoft.com/Log-Parser-Studio-cd458765" target="_blank">https://gallery.technet.microsoft.com/Log-Parser-Studio-cd458765</a>.</p>
<p>Once you donwload and unzip it, you will get a prompt to download LogParser.  Go ahead and do that.  Once you restart the studio, you will be able to query your data using T-SQL like language.  Click open folder yellow button and add your log files first.  Then you can use Search box to browse pre-built queries that ship with the tool, such as TOP 25 Slowest Url requests.</p>
<p>If you look at the query window, you will see the following:</p>
<p>SELECT TOP 25<br />
cs-uri-stem as URL,<br />
MAX(time-taken) As Max,<br />
MIN(time-taken) As Min,<br />
Avg(time-taken) As Average<br />
FROM &#8216;[LOGFILEPATH]&#8217;<br />
GROUP BY URL<br />
ORDER By Average DESC</p>
<p>&nbsp;</p>
<p>Now you can open a new query and start playing with your own data.  Executing top 25 slow URLs on my machine tool 1 second &#8211; that is on 172 MB worth of IIS logs.</p>
<p>I love this tool from Microsoft!</p>
<p>Enjoy.</p>
<p>&nbsp;</p>
]]></content:encoded>
					
					<wfw:commentRss>http://www.dotnetspeak.com/uncategorized/iis-log-parser/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Another .NET Core Tool</title>
		<link>http://www.dotnetspeak.com/uncategorized/another-net-core-tool/</link>
					<comments>http://www.dotnetspeak.com/uncategorized/another-net-core-tool/#respond</comments>
		
		<dc:creator><![CDATA[Sergey Barskiy]]></dc:creator>
		<pubDate>Wed, 10 Oct 2018 00:54:31 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">http://www.dotnetspeak.com/?p=1437</guid>

					<description><![CDATA[A while ago I wrote my first global tool: http://www.dotnetspeak.com/sql-server/my-fist-net-core-tool-is-live-on-nuget/&#160; I continued on my path to create more tools that eliminate the need for an ORM when writing .NET Core / .NET Standard apps and packages.&#160; Since I wrote a package to generate stored procedures, I wrote a companion one that creates data access classes ...</p><p><a href="http://www.dotnetspeak.com/uncategorized/another-net-core-tool/" class="more-link">Continue reading &#8216;Another .NET Core Tool&#8217; &#187;</a>]]></description>
										<content:encoded><![CDATA[<p>A while ago I wrote my first global tool: <a title="http://www.dotnetspeak.com/sql-server/my-fist-net-core-tool-is-live-on-nuget/" href="http://www.dotnetspeak.com/sql-server/my-fist-net-core-tool-is-live-on-nuget/">http://www.dotnetspeak.com/sql-server/my-fist-net-core-tool-is-live-on-nuget/</a>&nbsp; I continued on my path to create more tools that eliminate the need for an ORM when writing .NET Core / .NET Standard apps and packages.&nbsp; Since I wrote a package to generate stored procedures, I wrote a companion one that creates data access classes from an existing stored procedure.&nbsp; It is oriented toward ad-hoc queries.&nbsp; I am still wanting to do one specific to CRUD.&nbsp; You can install it using the following command:</p>
<p><strong>dotnet tool install &#8211;global dotnet-procstoclasses</strong></p>
<p></p>
<p>This tool generates C# classes from SQL Server stored procedures. Those classes include the following: criteria class, model classes, one for each result set that a procedure returns and executor class that runs the stored procedure and returns the result. The result class will contain a property for each result set. All operations are asynchronous and target .NET Standard project. You have to create a project ahead of time and needs to reference System.Data.SqlClient NuGet. Interfaces are generated for the executor class and for classes that map reader to models.</p>
<p><p><strong><br /></strong></p>
<p>In order to run the generator, you must create a configuration file in a folder that you are running the generator from. Here is an example of such file, by default named classes-config.json</p>
<pre>{
  "procedures": [
    {
      "name": "usp_Company_GetById_With_Children",
      "criteria": "TestCriteria",
      "wrapperData": "WrappedData",
      "executor": "TestExecutor",
      "classes": [
        "FirstClass",
        "SecondClass"
      ],
      "locations": {
        "interfaces": "..\\..\\..\\..\\ProcsToClassesIntegrationTests\\Interfaces",
        "implementations": "..\\..\\..\\..\\ProcsToClassesIntegrationTests\\Implementations"
      },
      "namespaces": {
        "classes": "Classes",
        "interfaces": "Abstractions"
      }
    }
  ]
}
</pre>
<p>It contains a list of procedure objects. All fields are required.</p>
<p>name is just procedure&#8217;s name</p>
<p>criteria is the name of the class for criteria object. Leave blank for procedures without parameters</p>
<p>wrappedData is the name of the class that is returned once procedure is executed. It will have properties, one for each list corresponding to a single result set</p>
<p>executor is the name of the class that will execute the procedure</p>
<p>classes is the list of strings aka class names, one for each result set, created in the order of result sets</p>
<p>locations will have to properties, for locations of interfaces and implementations classes or files that are generated</p>
<p>namespaces has two properties, again one for interfaces, one for implementations, containing namespace that these classes and interfaces will be put into</p>
<p>To run the generator just type</p>
<p><strong>procstoclasses -s SERVER -d DATABASE_NAME</strong> SERVER is the SQL Server instance, such as(local) or .. DATABASE_NAME is the name of the database. Windows security will be used for connecting, hence no user or password parameters.</p>
<p>Two more parameters are optional: -c FULL_PATH_AND_FILE_NAME_TO_CONFIG_JSON file as you see above</p>
<p>-p SINGLE_PROCEDURE_NAME_FROM_CONFIG_FILE. Use this to generate classes for just one procedure.</p>
<p></p>
<p>Please give me feedback on how to improve the tool.&nbsp; You can view the code on github: <a title="https://github.com/SergeyBarskiy/dotnet-procstoclasses" href="https://github.com/SergeyBarskiy/dotnet-procstoclasses">https://github.com/SergeyBarskiy/dotnet-procstoclasses</a></p>
]]></content:encoded>
					
					<wfw:commentRss>http://www.dotnetspeak.com/uncategorized/another-net-core-tool/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
