Category: CTH

Country Tag Helper–part 5

Now the Country Tag Helper supports .NET Standard 2.0 . This means that support .NET Core 2.0 .

Also, I have made a NuGET package in order to install on every .NET Core 2.0 application with explanations: https://www.nuget.org/packages/CountryTagHelper 

The only trouble here was to add references and make documentation in VS2017 about package ( see https://docs.microsoft.com/en-us/nuget/guides/create-net-standard-packages-vs2017 )

As I said , the source is at GitHub https://github.com/ignatandrei/CountryTagHelper and demo at http://countrytaghelper.apphb.com/

What remains to be done:

localized
add select2 with image flags   

provider / dependency injection for FromIP
readme.md / wiki on github

Country Tag Helper–part 4

 

Now I want to see somewhere in order to prove it Ii s right. I choose https://appharbor.com/ because it is free – and can not beat free for free source.

I made github integration and modify the .csproj file accordingly to https://support.appharbor.com/discussions/problems/90387-is-net-core-supported-yet 

The result is at http://countrytaghelper.apphb.com/ 

Also , I have to modify the code source to get the ip of the user :

string GetUserIP(ViewContext vc)
        {
            StringValues headerFwd;
            if (ViewContext.HttpContext?.Request?.Headers?.TryGetValue("X-Forwarded-For", out headerFwd) ?? false)
            {
                string rawValues = headerFwd.ToString();
                if (!string.IsNullOrWhiteSpace(rawValues))
                {
                    return rawValues.Split(',')[0];
                }

            }
            return ViewContext.HttpContext?.Connection?.RemoteIpAddress?.ToString();

        }

where ViewContext is

 [ViewContext]
        public ViewContext ViewContext { get; set; }

Country Tag Helper – part 3

Adding empty item – easy peasy. Just append "<option selected style=’display: none’ value=”></option>";

 

if (ASPCountryEmpty)
                {
                    string empty = "<option selected style='display: none' value=''></option>";
                    output.Content.AppendHtml(empty);
                }

For getting the IP, I was trying to balance the 2 variants: downloading GeoIP database (https://dev.maxmind.com/geoip/geoip2/geolite2/) or calling http://freegeoip.net/ .

I do call http://freegeoip.net/ – and the next point is to use Dependency Injection … or a provider to do that.

For the moment, the code is:

 private async Task<string> GetCountryCodeFromIP(string ip)
        {
            //ip= "188.25.145.65";
            var url = "http://freegeoip.net/csv/"+ip;
            var request = WebRequest.Create(url);
            request.Method = "GET";
            using (var wr = await request.GetResponseAsync())
            {
                using (var receiveStream = wr.GetResponseStream())
                {
                    using (var reader = new StreamReader(receiveStream, Encoding.UTF8))
                    {
                        string content = reader.ReadToEnd();
                        return content.Split(',')[1];
                    }
                        
                }
                    
            }


        }

CountryTagHelper–part 2

Finally, I have arrived at functionality. I said that I want something like

<select asp-country="true" asp-country-selected="US" >
   
</select>

 

The functionality is very easy to be added:

The entire class is :

using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.Extensions.Localization;
using System;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;

namespace CTHWeb.Controllers
{
    [HtmlTargetElement("select", Attributes = ASPCountryAttributeName)]
    public class CountryTagHelper:TagHelper
    {
        private const string ASPCountryAttributeName = "asp-country";
        private const string ASPCountrySelectedAttributeName = "asp-country-selected";

        [HtmlAttributeName(ASPCountryAttributeName)]
        public bool ASPCountry { get; set; }

        [HtmlAttributeName(ASPCountrySelectedAttributeName)]
        public string ASPCountrySelected{ get; set; }

        static string[] CountryISO;
        //static PropertyInfo[] properties;
        static CountryTagHelper()
        {
            var t =typeof( ResCTH);
            var properties= t.GetProperties(
                BindingFlags.Public |
                BindingFlags.Static |
                BindingFlags.GetProperty);
            CountryISO = properties
                .Where(it=>it.Name.Length==2)
                .Select(it => it.Name)
                .ToArray();
        }
        public override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
        {
            if (ASPCountry)
            {
                bool existSelected = !string.IsNullOrWhiteSpace(ASPCountrySelected);
                string option = "<option value='{0}' {2}>{1}</option>";
                foreach (var item in CountryISO)
                {
                    string selected = "";
                    string localizedName = ResCTH.ResourceManager.GetString(item);
                    if (existSelected)
                    {
                        bool currentItem = string.Equals(item, ASPCountrySelected, StringComparison.CurrentCultureIgnoreCase);
                        currentItem = currentItem || string.Equals(localizedName, ASPCountrySelected, StringComparison.CurrentCultureIgnoreCase);
                        if (currentItem)
                            selected = "selected";
                    }
                    output.Content.AppendFormat(option, item, localizedName,selected);
                }
            }
            return base.ProcessAsync(context, output);
        }
    }
}

 

The important thing is that it works with other html attributes, like

<select asp-country="true" asp-country-selected="US" disabled=”disabled”>
   
</select>

 

What it remains to be done:

  1. from IP – recognize the country of the visitor from IP
  2. localized – display messages in other language
  3. first item empty – now it selects Andorra
  4. Add select2 with image flags
  5. NuGet package
  6. readme.md / wiki on github
  7. tests

Country tag helper–part 1

 

What I want to do is to create a Country Tag Helper for asp.net core.

Something like

<select asp-country=”true”

and then list all countries in this select. More, it should be localized ( Germany vs Allemagne). That means 1 or more resource files 

 

First I need initial data: The WorldBank API gives us the names http://api.worldbank.org/countries and I have made a project https://github.com/ignatandrei/WorldBankAPi that inspects that API.

To retrieve data in resource format , it is simple:

 var r = new CountriesRepository();
            var arr = r.GetCountries().Result.
                Select(it =>
                $"<data name = \"{it.iso2Code}\" xml:space=\"preserve\" >" +

                $"<value>{it.name}</value>" +
                "</data>").ToArray();
            var s = string.Join(Environment.NewLine, arr);
            File.WriteAllText(@"D:\c.txt", s);

 

Then we could copy paste into resources:

 <data name = "AW" xml:space="preserve" ><value>Aruba</value></data>
  <data name = "AF" xml:space="preserve" ><value>Afghanistan</value></data>
  <data name = "AO" xml:space="preserve" ><value>Angola</value></data>
 ...

 

Now I want to make a list of those names – so I need this code to translate between C# generated code from resource

public static string AD {
            get {
                return ResourceManager.GetString("AD", resourceCulture);
            }
        }
public static string AE {
            get {
                return ResourceManager.GetString("AE", resourceCulture);
            }
        }
...

 

and a list of names to be put into select.

Reflection to the rescue:

  var t =typeof( ResCTH);
            properties= t.GetProperties(
                BindingFlags.Public |
                BindingFlags.Static |
                BindingFlags.GetProperty);
            CountryISO = properties
                .Where(it=>it.Name.Length==2)
                .Select(it => it.Name)
                .ToArray();

 

The code is on github https://github.com/ignatandrei/CountryTagHelper and I will improve next time.

Andrei Ignat weekly software news(mostly .NET)

* indicates required

Please select all the ways you would like to hear from me:

You can unsubscribe at any time by clicking the link in the footer of our emails. For information about our privacy practices, please visit our website.

We use Mailchimp as our marketing platform. By clicking below to subscribe, you acknowledge that your information will be transferred to Mailchimp for processing. Learn more about Mailchimp's privacy practices here.