<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Nandkishor</title>
    <description>The latest articles on DEV Community by Nandkishor (@nandkishoryadav).</description>
    <link>https://dev.to/nandkishoryadav</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F390856%2F06d152bd-ed71-49aa-a07f-30bb1e32884c.jpeg</url>
      <title>DEV Community: Nandkishor</title>
      <link>https://dev.to/nandkishoryadav</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nandkishoryadav"/>
    <language>en</language>
    <item>
      <title>Create Protected Routes In NextJS and NextAuth</title>
      <dc:creator>Nandkishor</dc:creator>
      <pubDate>Tue, 07 Dec 2021 19:53:10 +0000</pubDate>
      <link>https://dev.to/nandkishoryadav/create-protected-routes-in-nextjs-and-nextauth-19ml</link>
      <guid>https://dev.to/nandkishoryadav/create-protected-routes-in-nextjs-and-nextauth-19ml</guid>
      <description>&lt;p&gt;Protecting Routes from unauthenticated users is a crucial part of any app.&lt;/p&gt;

&lt;p&gt;In this article, I'll show you exactly how to create protected routes in your NextJS application using NextAuth.&lt;/p&gt;

&lt;p&gt;I'll use a JWT token as an example, with the &lt;strong&gt;accessToken&lt;/strong&gt;  being saved in the session. Check this article for more information.&lt;br&gt;
&lt;a href="https://cloudcoders.xyz/blog/nextauth-credentials-provider-with-external-api-and-login-page/"&gt;How to implement NextAuth credentials provider with external API and login page&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Because of the way Next.js handles &lt;strong&gt;getServerSideProps&lt;/strong&gt; and &lt;strong&gt;getInitialProps&lt;/strong&gt;, every protected page load must make a server-side request to determine whether the session is valid before generating the requested page (SSR). This increases server load, but there is an option if you are comfortable making requests from the client. You can use **useSession **to ensure that you always have a valid session. If no session is identified after the initial loading state, you can determine the appropriate action to take.&lt;/p&gt;

&lt;p&gt;First, let's modify our &lt;strong&gt;_app.js&lt;/strong&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SessionProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useSession&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;signIn&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next-auth/react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;pageProps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;pageProps&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;SessionProvider&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Auth&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;pageProps&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Auth&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;pageProps&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;)}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/SessionProvider&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Auth&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useSession&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;
  &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;loading&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isUser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;signIn&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isUser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Session is being fetched, or no user.&lt;/span&gt;
  &lt;span class="c1"&gt;// If no user, useEffect() will redirect.&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Loading&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Line #23: Do nothing while in the loading state.&lt;/p&gt;

&lt;p&gt;Line #24: If the user is not authenticated, force the user to the login page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Custom Client Session Handling
&lt;/h2&gt;

&lt;p&gt;Because of how Next.js handles &lt;strong&gt;getServerSideProps&lt;/strong&gt; / &lt;strong&gt;getInitialProps&lt;/strong&gt;, every protected page load must make a server-side request to determine whether the session is valid and then build the requested page. This alternate technique enables for the display of a loading status on the initial check, and all subsequent page transitions will be client-side, eliminating the need to check with the server and regenerate pages.&lt;/p&gt;

&lt;p&gt;Consider the "/dashboard" page. Only authorized users should be able to view this page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Dashboard&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useSession&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Some super secret dashboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;Dashboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The session is always non-null inside this page, all the way down the React tree.&lt;/p&gt;

&lt;p&gt;Notice that we are using &lt;strong&gt;Dashboard.auth = true&lt;/strong&gt; to check if the user is authenticated, if not redirect to the login page.&lt;/p&gt;

&lt;p&gt;We need to add &lt;strong&gt;auth = true&lt;/strong&gt; to every page that we want to protect from the unauthenticated user.&lt;/p&gt;

&lt;p&gt;It is simple to extend/modify to support something similar to an options object for role-based authentication on pages. As an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Dashboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;admin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;LoadingSkeleton&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;unauthorized&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/login-with-different-user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// redirect to this url&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I hope this post helps.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>nextauth</category>
    </item>
    <item>
      <title>Localization with JSON files in .NET 6</title>
      <dc:creator>Nandkishor</dc:creator>
      <pubDate>Tue, 30 Nov 2021 15:30:26 +0000</pubDate>
      <link>https://dev.to/nandkishoryadav/localization-with-json-files-in-net-6-4kcd</link>
      <guid>https://dev.to/nandkishoryadav/localization-with-json-files-in-net-6-4kcd</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--X5GiJKZV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res-4.cloudinary.com/nandkishor-yadav/image/upload/q_auto/v1/cloudcoders-images/JSON-Based-Localization-in-NET-6.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--X5GiJKZV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res-4.cloudinary.com/nandkishor-yadav/image/upload/q_auto/v1/cloudcoders-images/JSON-Based-Localization-in-NET-6.jpg" alt="Localization with JSON files in .NET 6" width="700" height="466"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We'll learn how to use JSON-based localization in.NET 6 and how to combine it with caching to make it even more efficient. We'll save the localized strings in JSON files and utilize middleware to swap languages using language keys in the request header.&lt;/p&gt;

&lt;p&gt;Source code can be found &lt;a href="https://github.com/nandkishor-yadav/dotnet-6-json-localization"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Table of contents&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What we'll build?&lt;/li&gt;
&lt;li&gt;Getting started with JSON based localization in .NET 6&lt;/li&gt;
&lt;li&gt;Testing with Postman&lt;/li&gt;
&lt;li&gt;Summary&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  What we'll Build?
&lt;/h3&gt;

&lt;p&gt;We'll create a .NET 6 Web API that provides messages based on the Accepted Language in the request header. We'll use IDistributedCache to cache the string. The main purpose of this approach is to read language strings from a JSON file instead of a RESX file. We'll do this by adding a new IStringLocalizer implementation. This will be straightforward, but it will be extremely useful. Who doesn't want to work with JSON files?&lt;/p&gt;

&lt;p&gt;It'll just need three new classes and a few service registrations. Let's get this started!&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting started with JSON based localization in .NET 6
&lt;/h3&gt;

&lt;p&gt;Create a new ASP.NET Core Web API project in your favorite IDE (I use Visual Studio 2022 Community). Make sure you're using the .NET 6.0 Framework.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KS_ogSYT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res-1.cloudinary.com/nandkishor-yadav/image/upload/q_auto/v1/cloudcoders-images/JSON-Based-Localization-in-.NET-6.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KS_ogSYT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res-1.cloudinary.com/nandkishor-yadav/image/upload/q_auto/v1/cloudcoders-images/JSON-Based-Localization-in-.NET-6.webp" alt="Localization with JSON files in .NET 6" width="880" height="582"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm not going to include any other class files in this implementation because I want it to be as basic as possible. To clear up the project, I deleted the weather controllers and related files from the WebAPI solution.&lt;/p&gt;

&lt;p&gt;There are two aspects to this implementation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Middleware that can determine the language code passed in at the request header by the client (which will be a postman in our case).&lt;/li&gt;
&lt;li&gt;An implementation of the IStringLocalizer to support JSON files. I intend to store the JSON file by the locale name (en-US.json) under a Resources folder. Note that we will also use IDistributedCache to make our system more efficient.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s create a new class and name it JsonStringLocalizer.cs&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    public class JsonStringLocalizer : IStringLocalizer
    {
        private readonly IDistributedCache _cache;
        private readonly JsonSerializer _serializer = new();

        public JsonStringLocalizer(IDistributedCache cache)
        {
            _cache = cache;
        }

        public LocalizedString this[string name]
        {
            get
            {
                var value = GetString(name);
                return new LocalizedString(name, value ?? name, value == null);
            }
        }

        public LocalizedString this[string name, params object[] arguments]
        {
            get
            {
                var actualValue = this[name];
                return !actualValue.ResourceNotFound
                    ? new LocalizedString(name, string.Format(actualValue.Value, arguments), false)
                    : actualValue;
            }
        }

        public IEnumerable&amp;lt;LocalizedString&amp;gt; GetAllStrings(bool includeParentCultures)
        {
            var filePath = $"Resources/{Thread.CurrentThread.CurrentCulture.Name}.json";
            using var str = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
            using var sReader = new StreamReader(str);
            using var reader = new JsonTextReader(sReader);
            while (reader.Read())
            {
                if (reader.TokenType != JsonToken.PropertyName)
                    continue;
                string? key = reader.Value as string;
                reader.Read();
                var value = _serializer.Deserialize&amp;lt;string&amp;gt;(reader);
                yield return new LocalizedString(key, value, false);
            }
        }
        private string? GetString(string key)
        {
            string? relativeFilePath = $"Resources/{Thread.CurrentThread.CurrentCulture.Name}.json";
            var fullFilePath = Path.GetFullPath(relativeFilePath);
            if (File.Exists(fullFilePath))
            {
                var cacheKey = $"locale_{Thread.CurrentThread.CurrentCulture.Name}_{key}";
                var cacheValue = _cache.GetString(cacheKey);
                if (!string.IsNullOrEmpty(cacheValue))
                {
                    return cacheValue;
                }

                var result = GetValueFromJSON(key, Path.GetFullPath(relativeFilePath));

                if (!string.IsNullOrEmpty(result))
                {
                    _cache.SetString(cacheKey, result);

                }
                return result;
            }
            return default;
        }
        private string? GetValueFromJSON(string propertyName, string filePath)
        {
            if (propertyName == null) {
                return default;
            }
            if (filePath == null) {
                return default;
            }
            using var str = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
            using var sReader = new StreamReader(str);
            using var reader = new JsonTextReader(sReader);
            while (reader.Read())
            {
                if (reader.TokenType == JsonToken.PropertyName &amp;amp;&amp;amp; reader.Value as string == propertyName)
                {
                    reader.Read();
                    return _serializer.Deserialize&amp;lt;string&amp;gt;(reader);
                }
            }
            return default;
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Line #3: We use IDistributedCache here.&lt;/p&gt;

&lt;p&gt;Line #31 - 46: With GetAllStrings(), we try to read the JSON file name according to CurrentCulture and return a list of LocalizedString objects. The key and values of all the entries in the retrieved JSON file would be included in this list. Deserialization is performed on each of the read JSON values.&lt;/p&gt;

&lt;p&gt;Line #47 - 70: String localization is handled by the GetString() method. In this case, the file path is also determined by the request's current culture. If the file exists, a cache key with a unique name is generated. The system would look in cache memory to determine if the matched key contains any value. If a value is discovered in the cache, it is returned. Otherwise, the app opens the JSON file and tries to get and return the string it finds.&lt;/p&gt;

&lt;p&gt;Line #11 - 18: _*&lt;em&gt;this[string name]  *&lt;/em&gt;_This is the entry method in our controller that we will use. It accepts a key and uses the previously described approach to try to find the associated values in the JSON file. It's worth noting that if no value is discovered in the JSON file, the method will return the same key.&lt;/p&gt;

&lt;p&gt;Next, we'll create a Factory class that will be responsible for generating the JsonStringLocalizer instance internally. Name the new class as JsonStringLocalizerFactory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    public class JsonStringLocalizerFactory : IStringLocalizerFactory
    {
        private readonly IDistributedCache _cache;

        public JsonStringLocalizerFactory(IDistributedCache cache)
        {
            _cache = cache;
        }

        public IStringLocalizer Create(Type resourceSource) =&amp;gt;
            new JsonStringLocalizer(_cache);

        public IStringLocalizer Create(string baseName, string location) =&amp;gt;
            new JsonStringLocalizer(_cache);
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then comes the fun part: writing a Middleware that can read the Accept-Language key from the request header and set the current thread's language if the culture is valid.&lt;/p&gt;

&lt;p&gt;Create a new class and name it LocalizationMiddleware.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    public class LocalizationMiddleware : IMiddleware
    {
        public async Task InvokeAsync(HttpContext context, RequestDelegate next)
        {
            var cultureKey = context.Request.Headers["Accept-Language"];
            if (!string.IsNullOrEmpty(cultureKey))
            {
                if (DoesCultureExist(cultureKey))
                {
                    var culture = new CultureInfo(cultureKey);
                    Thread.CurrentThread.CurrentCulture = culture;
                    Thread.CurrentThread.CurrentUICulture = culture;
                }
            }
            await next(context);
        }
        private static bool DoesCultureExist(string cultureName)
        {
            return CultureInfo.GetCultures(CultureTypes.AllCultures)
                .Any(culture =&amp;gt; string.Equals(culture.Name, cultureName,
              StringComparison.CurrentCultureIgnoreCase));
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Line #5: The Accept-Language of the current HTTP context is read here from the request header.&lt;/p&gt;

&lt;p&gt;Line #8-13: The current thread culture is set if a valid culture is found.&lt;/p&gt;

&lt;p&gt;Let's start by adding some language files. Create a new Resources folder and add two new JSON files to it. The JSON files will be named en-US.json and de-DE.json&lt;/p&gt;

&lt;p&gt;Sample of en-US.json&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "hi": "Hello",
  "welcome": "Welcome {0}, How are you?"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next,de-DE.json. PS, the following was translated via Google Translate.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "hi": "Hallo",
  "welcome": "Willkommen {0}, wie geht es dir?"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, we have two keys, hello and welcome, that the program is supposed to translate based on the request header.&lt;/p&gt;

&lt;p&gt;Now comes the crucial phase, where we register our middleware and the JSONLocalizer as services. Add the following to the ConfigureServices function in Startup.cs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;services.AddLocalization();
services.AddSingleton&amp;lt;LocalizationMiddleware&amp;gt;();
services.AddDistributedMemoryCache();
services.AddSingleton&amp;lt;IStringLocalizerFactory, JsonStringLocalizerFactory&amp;gt;();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the following to the Configure method. It's worth noting that we've set en-US as our application's default culture. This can also be made configurable by moving it to the appsettings.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var options = new RequestLocalizationOptions
{
    DefaultRequestCulture = new RequestCulture(new CultureInfo("en-US"))
};
app.UseRequestLocalization(options);
app.UseStaticFiles();
app.UseMiddleware&amp;lt;LocalizationMiddleware&amp;gt;();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, let's create a new API Controller to show how our JSON localizer works. Create a new Controller with the name HomeController.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    public class HomeController : ControllerBase
    {
        private readonly IStringLocalizer&amp;lt;HomeController&amp;gt; _stringLocalizer;

        public HomeController(IStringLocalizer&amp;lt;HomeController&amp;gt; stringLocalizer)
        {
            _stringLocalizer = stringLocalizer;
        }
        [HttpGet]
        public IActionResult Get()
        {
            var message = _stringLocalizer["hi"].ToString();
            return Ok(message);
        }
        [HttpGet("{name}")]
        public IActionResult Get(string name)
        {
            var message = string.Format(_stringLocalizer["welcome"], name);
            return Ok(message);
        }
        [HttpGet("all")]
        public IActionResult GetAll()
        {
            var message = _stringLocalizer.GetAllStrings();
            return Ok(message);
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Line #3: Constructor Injection of IStringLocalizer instance.&lt;/p&gt;

&lt;p&gt;Line #10 - 14: Here's a test to see whether we can output the localized version of the key 'hi' to the console and then return it as a response.&lt;/p&gt;

&lt;p&gt;Line #16 - 20: The application should return a localized version of "Welcome xxxx, how are you?" when we give this endpoint a random name. That's all there is to it.&lt;/p&gt;

&lt;p&gt;Line #22 - 26: This method would ideally return all the keys and values found in the corresponding JSON file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing with Postman
&lt;/h3&gt;

&lt;p&gt;Let's fire up Postman and perform some basic tests.&lt;/p&gt;

&lt;p&gt;Here is what you get as a response when you send a GET request to the /api/home endpoint with the Accept-Language as de-DE&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kxTVeVJ---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res-4.cloudinary.com/nandkishor-yadav/image/upload/q_auto/v1/cloudcoders-images/JSON-Based-Localization-in-.NET-6-de-DE.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kxTVeVJ---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res-4.cloudinary.com/nandkishor-yadav/image/upload/q_auto/v1/cloudcoders-images/JSON-Based-Localization-in-.NET-6-de-DE.webp" alt="Localization with JSON files in .NET 6" width="880" height="306"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Accept-Language is set to en-US.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jBnHt211--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res-3.cloudinary.com/nandkishor-yadav/image/upload/q_auto/v1/cloudcoders-images/JSON-Based-Localization-in-.NET-6-en-US.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jBnHt211--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res-3.cloudinary.com/nandkishor-yadav/image/upload/q_auto/v1/cloudcoders-images/JSON-Based-Localization-in-.NET-6-en-US.webp" alt="Localization with JSON files in .NET 6" width="880" height="301"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, I try to send a GET request to the /api/home endpoint along with the name. Accept-Language set to en-US&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jeVsQjZc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res-3.cloudinary.com/nandkishor-yadav/image/upload/q_auto/v1/cloudcoders-images/JSON-Based-Localization-in-.NET-6-en-US-name.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jeVsQjZc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res-3.cloudinary.com/nandkishor-yadav/image/upload/q_auto/v1/cloudcoders-images/JSON-Based-Localization-in-.NET-6-en-US-name.webp" alt="Localization with JSON files in .NET 6" width="880" height="223"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Accept-Language set to de-DE.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--piMcq5y8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res-4.cloudinary.com/nandkishor-yadav/image/upload/q_auto/v1/cloudcoders-images/JSON-Based-Localization-in-.NET-6-de-DE-name.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--piMcq5y8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res-4.cloudinary.com/nandkishor-yadav/image/upload/q_auto/v1/cloudcoders-images/JSON-Based-Localization-in-.NET-6-de-DE-name.webp" alt="Localization with JSON files in .NET 6" width="880" height="296"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, when you send a GET request to the /api/home/all endpoint, you get to see all the key/value pairs of our strings in the JSON file related to the relevant accept-language.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Tdp4G890--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res-2.cloudinary.com/nandkishor-yadav/image/upload/q_auto/v1/cloudcoders-images/JSON-Based-Localization-in-.NET-6-all.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Tdp4G890--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res-2.cloudinary.com/nandkishor-yadav/image/upload/q_auto/v1/cloudcoders-images/JSON-Based-Localization-in-.NET-6-all.webp" alt="Localization with JSON files in .NET 6" width="880" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Isn't it great to have in your projects?&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;We learned a quick and easy technique to implement JSON-based localization in .NET 6 applications in this article. The source code can be found &lt;a href="https://github.com/nandkishor-yadav/dotnet-6-json-localization"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>net6</category>
      <category>localization</category>
    </item>
    <item>
      <title>DateOnly and TimeOnly in .NET 6</title>
      <dc:creator>Nandkishor</dc:creator>
      <pubDate>Fri, 04 Jun 2021 20:05:15 +0000</pubDate>
      <link>https://dev.to/nandkishoryadav/dateonly-and-timeonly-in-net-6-5g4c</link>
      <guid>https://dev.to/nandkishoryadav/dateonly-and-timeonly-in-net-6-5g4c</guid>
      <description>&lt;p&gt;Two long-awaited types have been added to the core library in.NET 6 (preview 4). Developers can use DateOnly and TimeOnly to express either the date or time element of a DateTime. These two new types are structs (value types) and can be used when your code has to deal with date or time notions separately. The System namespace contains both types. Using these new types may be consistent with how databases allow for the representation of similar data. These types, in particular, are compatible with the SQL Server date and time data types.&lt;/p&gt;

&lt;h2&gt;
  
  
  USING DATEONLY IN .NET 6
&lt;/h2&gt;

&lt;p&gt;In terms of what they represent, the types are very self-explanatory. We may use DateOnly to express a date without a time component. For example, we may represent someone’s date of birth in our application. In such instances, we seldom need to use the time component of a DateTime, and a conventional approach would be to set the time to 00:00:00.000. We may be more specific about our intentions when using DateOnly.&lt;br&gt;
We may create an instance of DateOnly by supplying the year, month, and day as arguments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var date = new DateOnly(2021, 06, 04);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a DateOnly that represents 4th June 2021.&lt;br&gt;
If we want to create a DateOnly instance from the existing DateTime, it can be achieved by calling the FromDateTime method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var currentDate = DateOnly.FromDateTime(DateTime.Now); 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We may parse a string expressing a date into a DateOnly form using either Parse, which may cause an exception or TryParse, which returns a bool indicating success or failure, much like we can with the existing DateTime type.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (DateOnly.TryParse("04/06/2021", new CultureInfo("en-US"), DateTimeStyles.None, out var result))
{
    Console.WriteLine(result);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can also add days, months, or years to a DateOnly instance, which will result in a new instance with the updated date.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var newDate = date.AddDays(1).AddMonths(1).AddYears(1);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  USING TIMEONLY IN .NET 6
&lt;/h2&gt;

&lt;p&gt;The TimeOnly struct is used to represent a time that is not related to a date. Consider developing a reminder app that will remind the users about the specific task every day. In this case, the date part is not important as we want to remember the time of the day when the reminder should pop up.&lt;br&gt;
There are various constructor overloads for the TimeOnly type. The more popular ones, which I expect most developers to use, allow us to create a date that accepts either the hour and minute, the hour, minute, and second, or the hour, minute, second, and millisecond for the time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public TimeOnly(int hour, int minute)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public TimeOnly(int hour, int minute)
public TimeOnly(int hour, int minute, int second)
public TimeOnly(int hour, int minute, int second, int millisecond)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;we can represent 08:30 am by creating the following TimeOnly instance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var startTime = new TimeOnly(08, 30);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The hour portion is expected to be provided using the 24-hour clock format, where 1 pm is 13 hours.&lt;br&gt;
TimeOnly internally holds a long that represents the number of ticks (100 nanosecond intervals) that have passed since midnight by the specified time. For example, 1 a.m. is one hour into the day, which is 36,000,000,000 ticks since midnight (00:00:00.0000000). we can construct a TimeOnly by providing the ticks as an input.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public TimeOnly(long ticks);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var endTime = new TimeOnly(14, 00, 00);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can also perform mathematical operations on these TimeOnly instances, such as calculating the difference.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var diff = endTime - startTime;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I hope you learned something new from this article.&lt;/p&gt;

</description>
      <category>dotnet</category>
    </item>
  </channel>
</rss>
