C# – Pro9ramming https://pro9ramming.com Software craftsman's blog Wed, 15 Apr 2020 17:51:04 +0000 en-US hourly 1 https://wordpress.org/?v=6.5.3 Generate Machine Key JSON Token https://pro9ramming.com/generate-machine-key-json-token/ Tue, 16 May 2017 12:03:46 +0000 http://pro9ramming.com/blog/?p=480 When creating a password reset functionality, cryptographic token generation is often required. Idea is to serialize an object to JSON (using Newtonsoft.Json) and protect it using MachineKey. To be able to safely transfer the token over URL (GET request), HEX string can be used.

public class MachineKeyToken
    {
        public static string GetToken(object tokenData, string purpose)
        {
            var json = JsonConvert.SerializeObject(tokenData);
            var plainBytes = Encoding.UTF8.GetBytes(json);
            var protectedBytes = MachineKey.Protect(plainBytes, purpose);
            return BytesToHexString(protectedBytes);
        }

        public static T GetFromToken<T>(string token, string purpose)
        {
            var stringBytes = HexStringToBytes(token);
            var unprotectedBytes = MachineKey.Unprotect(stringBytes, purpose);
            var plainBytes = Encoding.UTF8.GetString(unprotectedBytes);
            return JsonConvert.DeserializeObject<T>(plainBytes);
        }

        private static string BytesToHexString(byte[] bytes)
        {
            return BitConverter.ToString(bytes).Replace("-", "");
        }

        private static byte[] HexStringToBytes(string hexString)
        {
            if (string.IsNullOrEmpty(hexString))
                throw new InvalidOperationException("String is either null or empty.");

            if (hexString.Length % 2 != 0)
                throw new InvalidOperationException("Hex string length must be even.");

            return Enumerable.Range(0, hexString.Length)
                         .Where(x => x % 2 == 0)
                         .Select(x => Convert.ToByte(hexString.Substring(x, 2), 16))
                         .ToArray();
        }

    }

 

]]>
Send E-mail using ASP.NET https://pro9ramming.com/send-email-using-asp-net/ Wed, 19 Apr 2017 13:38:33 +0000 http://pro9ramming.com/blog/?p=470 Continue reading Send E-mail using ASP.NET]]> E-mail can be sent using System.Net.Mail namespace classes (not deprecated System.Web.Mail). First place the following configuration in Web.config:

<system.net>
    <mailSettings>
      <smtp from="from email">
        <network host="smtp.googlemail.com" 
                 port="587" 
                 userName="username" 
                 password="pass" 
                 defaultCredentials="false" 
                 enableSsl="true" />
      </smtp>
    </mailSettings>
  </system.net>

For testing purposes Google Mail server can be used. Google Mail requres SSL, so enableSsl=”true” has to be placed in the config. In order to send mail, SmtpClient and MailMessage classes are used:

using (SmtpClient client = new SmtpClient())
{
      MailMessage msg = new MailMessage();
      msg.To.Add("to email");
      msg.Subject = "Subject";
      msg.Body = "Body";
      msg.IsBodyHtml = true;
      client.Send(msg);
}

Configuration from Web.config is going to be automatically recognized. From address can be overriden using msg.From property. If body contains HTML, msg.IsBodyHtml property can be used.

]]>
WinForms DataGridView BindingList example https://pro9ramming.com/winforms-datagridview-bindinglist-example/ Tue, 18 Apr 2017 12:09:58 +0000 http://pro9ramming.com/blog/?p=468 Continue reading WinForms DataGridView BindingList example]]> Binding of component to model is a usual requirement for both desktop and web applications nowadays. This tutorial shows how to bind a list of persons to DataGridView using Windows Forms (and of course C#).

First of all, create a model class:

public class Person : INotifyPropertyChanged
    {
       [Browsable(false)]
        public int Id { get; set; }

        [DisplayName("First name")]
        public string FirstName { get; set; }

        [DisplayName("Last name")]
        public string LastName { get; set; }

        private int _age;
        public int Age
        {
            get {
                return _age;
            }
            set {
                _age = value;
                OnPropertyChanged(nameof(Age));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

INotifyPropertyChanged interface is used to notify a client that certain value has changed. [Browsable(false)] attribute is used to mark a property not visible in DataGridView. In order to change the column header, use [DisplayName] attribute.

After creating a model, let’s add some data to it (place the following code inside of Form):

private BindingList<Person> persons = new BindingList<Person>
            {
                new Person {
                    Id = 1,
                    FirstName = "John",
                    LastName = "Smith",
                    Age = 25
                },
                new Person {
                    Id = 2,
                    FirstName = "Nick",
                    LastName = "Adams",
                    Age = 64
                }
            };

After that add a DataGridView on a form. On Form_Load() execute the following lines:

dataGridView1.DataSource = new BindingSource
            {
                DataSource = persons
            };
            dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.DisplayedCells;

That binds the data with the component and uses auto sizing of columns.

Functionality can be tested, for example by using button_Click() and changing the Age property:

persons[0].Age = 27;

Data should change in the grid automatically.

]]>
ASP.NET MVC file upload to Azure Blob storage https://pro9ramming.com/asp-net-mvc-file-upload-to-azure-blob-storage/ Thu, 13 Apr 2017 12:41:09 +0000 http://pro9ramming.com/blog/?p=465 Continue reading ASP.NET MVC file upload to Azure Blob storage]]> Azure has it’s own blob storage functionality called Azure Blob storage. It’s a classic object storage cloud service like Amazon S3 and OpenStack Swift. Also, Riak works in similar fashion. Logic behind is pretty simple, account can have multiple containers which can have multiple files (objects or blobs). It can handle huge amounts of unstructured data.

First create a new ASP.NET MVC project and create a FileController. After that create a method which returns specific container.

private CloudBlobContainer GetContainer()
        {
            var storageAccount = CloudStorageAccount.Parse(ConfigurationManager.AppSettings["StorageAccount"]);
            var blobClient = storageAccount.CreateCloudBlobClient();
            var container = blobClient.GetContainerReference(ConfigurationManager.AppSettings["StorageContainer"]);
            return container;
        }

Account and container data can be saved in <appSettings> in Web.config:

<appSettings>
    <add key="StorageAccount" value="ACCOUNT CONNECTION STRING"/>
    <add key="StorageContainer" value="CONTAINER NAME" />
</appSettings>

Razor syntax for file upload looks like this:

@using (Html.BeginForm("UploadFile", "File", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
    <input type="file" name="file" />
    <br />
    <input type="submit" value="Upload" />
}

Action method UploadFile() contains some validation logic. GetBlockBlobReference() creates a new blob with specified fileName:

[HttpPost]
        public ActionResult UploadFile()
        {
            if (Request.Files.Count > 0)
            {
                var file = Request.Files[0];
                if (file != null && file.ContentLength > 0)
                    SaveToStorage(file.InputStream, file.FileName);
            }
            return View();
        }

        public void SaveToStorage(Stream inputStream, string fileName)
        {
            var container = GetContainer();
            var blob = container.GetBlockBlobReference(fileName);

            using (inputStream)
                blob.UploadFromStream(inputStream);
        }

Blob can be downloaded by using MemoryStream:

[HttpGet]
        public ActionResult DownloadFile(string fileName)
        {
            try
            {
                var container = GetContainer();
                var blob = container.GetBlockBlobReference(fileName);

                var memStream = new MemoryStream();
                blob.DownloadToStream(memStream);

                Response.ContentType = blob.Properties.ContentType;
                Response.AddHeader("Content-Disposition", "Attachment;filename=" + fileName);
                Response.AddHeader("Content-Length", blob.Properties.Length.ToString());
                Response.BinaryWrite(memStream.ToArray());

                return new HttpStatusCodeResult(200);
            }
            catch (Exception ex)
            {
                return Content(ex.ToString());
            }
        }

 

]]>
OWIN cookie authentication with roles (part 2) https://pro9ramming.com/owin-cookie-authentication-with-roles-part-2/ Fri, 17 Feb 2017 12:50:10 +0000 http://pro9ramming.com/blog/?p=443 Continue reading OWIN cookie authentication with roles (part 2)]]> In Part 1 of this tutorial, basic OWIN cookie authentication with roles has been set. This part describes further features than are added upon Part 1.

ReturnUrl 

First feature is ReturnUrl functionality (the possibility to return the user to the right place when after login). First of all, signature of Login() action method has to be changed a bit, by adding returnUrl parameter:

public ActionResult Login(LoginViewModel model, string returnUrl)

After checking credentials, adding claims and creating a cookie, returnUrl has to be checked:

if (!string.IsNullOrEmpty(returnUrl) && Url.IsLocalUrl(returnUrl))
   return Redirect(returnUrl);
else
   return RedirectToAction("UserPanel");

If it’s not local or not specified, redirect to User panel.

In /Account/Login, Login form should look like this:

@using (Html.BeginForm("Login", "Account", new { returnUrl = Request.QueryString["ReturnUrl"] }, FormMethod.Post))

Make sure to place anonymous object in place where routeValues parameter is specified (not where htmlAttributes are).

AntiForgeryToken

In order to avoid CSRF attacks, AntiForgeryToken should be used in forms. Add the following line inside the form:

@Html.AntiForgeryToken()

And the [ValidateAntiForgeryToken] attribute to Login() method:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginViewModel model, string returnUrl)

Using AntiForgeryToken with claims identity requires additional step. Add the following line in Application_Start() method in Global.asax.cs:

protected void Application_Start()
{
   //...
   AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.Name;
}

Changing/updating of claims

Claims have to be updated when user’s role is changed. Add the following code in AccountController:

[Authorize(Roles = "User")]
        public ActionResult SetAdminRole()
        {
            var identity = new ClaimsIdentity(User.Identity);
            identity.RemoveClaim(identity.FindFirst(ClaimTypes.Role));
            identity.AddClaim(new Claim(ClaimTypes.Role, "Administrator"));
            HttpContext.GetOwinContext().Authentication.AuthenticationResponseGrant = new AuthenticationResponseGrant(new ClaimsPrincipal(identity), new AuthenticationProperties { IsPersistent = true });
            return RedirectToAction("UserPanel");
        }

And link in /Account/UserPanel:

<p>@Html.ActionLink("Set admin role", "SetAdminRole", "Account")</p>

When user clicks specified link, his role (claim) is going to be changed.

ExpireTimeSpan and SlidingExpiration

These settings are set in CookieAuthenticationOptions:

app.UseCookieAuthentication(new CookieAuthenticationOptions {
                AuthenticationType = "ApplicationCookie",
                LoginPath = new PathString("/Home/Index"),
                CookieSecure = CookieSecureOption.SameAsRequest,
                ExpireTimeSpan = TimeSpan.FromSeconds(10),
                SlidingExpiration = true
            });

ExpireTimeSpan indicates the time cookie is valid. If SlidingExpiration is true, than middleware re-issues a new cookie with new expiration time when request is more than halfway through the expiration window. Default value for ExpireTimeSpan is 14 days, and SlidingExpiration is true. For testing purposes, in the above code, ExpirationTimeSpan is set to 10 seconds (TimeSpan.FromSeconds(10)).

 

]]>
OWIN cookie authentication with roles (part 1) https://pro9ramming.com/owin-cookie-authentication-with-roles-part-1/ Fri, 17 Feb 2017 12:19:34 +0000 http://pro9ramming.com/blog/?p=439 Continue reading OWIN cookie authentication with roles (part 1)]]> The aim of this tutorial is to create local cookie-based authentication using OWIN (without Identity). Additionally, roles authorization is going to be integrated into the project.

Start by creating an empty ASP.NET Web Application (for purposes of this project, it’s called “Example Project”).

Add new HomeController (with Index view) and AccountController (with Login, UserPanel and AdminPanel views).

Install following NuGet packages:

Microsoft.Owin.Host.SystemWeb

Microsoft.Owin.Security.Cookies

Microsoft.AspNet.Identity.Core

Create Startup class in the root of the project:

using Microsoft.Owin;
using Microsoft.Owin.Security.Cookies;
using Owin;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

[assembly: OwinStartup(typeof(ExampleProject.Startup))]
namespace ExampleProject
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {

            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                LoginPath = new PathString("/Account/Login"),
                CookieSecure = CookieSecureOption.SameAsRequest
            });

        }
    }
}

When running this in production environment with HTTPS (SSL), use CookieSecureOption.Always to always issue a cookie with security flag.

Add the following ViewModel to Models folder:

public class LoginViewModel
    {
        public string Username { get; set; }
        public string Password { get; set; }
        public bool RememberMe { get; set; }
    }

AccountController looks like this:

public class AccountController : Controller
    {
        public ActionResult Login()
        {
            return View();
        }

        [HttpPost]
        public ActionResult Login(LoginViewModel model) //possibly add returnUrl
        {
            if (ModelState.IsValid)
            {
                if ((model.Username == "admin" && model.Password == "admin") || (model.Username == "user" && model.Password == "user"))
                {
                    var claims = new List<Claim>();
                    claims.Add(new Claim(ClaimTypes.Name, model.Username)); //available through User.Identity.Name
                    claims.Add(new Claim(ClaimTypes.Role, GetRole(model.Username)));
                    var identity = new ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie);
                    Request.GetOwinContext().Authentication.SignIn(new AuthenticationProperties
                    {
                        IsPersistent = model.RememberMe
                    }, identity);
                    return RedirectToAction("UserPanel");
                }
                else
                    ModelState.AddModelError("", "Provided credentials not valid");
            }
            else
            {
                ModelState.AddModelError("", "Model state not valid");
            }
            return View("Index");
        }

        private string GetRole(string username)
        {
            return username == "admin" ? "Administrator" : "User";
        }

        [Authorize(Roles = "User, Administrator")]
        public ActionResult UserPanel()
        {
            Debug.WriteLine("UserPanel User.Identity.Name: " + User.Identity.Name);
            var claims = ((ClaimsIdentity)User.Identity).Claims;
            Debug.WriteLine("Role is: " + claims.SingleOrDefault(k => k.Type == ClaimTypes.Role).Value);
            return View();
        }

        [Authorize(Roles = "Administrator")]
        public ActionResult AdminPanel()
        {
            Debug.WriteLine("AdminPanel User.Identity.Name: " + User.Identity.Name);
            return View();
        }

        [Authorize(Roles = "Administrator, User")]
        public ActionResult Logout()
        {
            //DefaultAuthenticationTypes.ApplicationCookie actually not needed
            Request.GetOwinContext().Authentication.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
            return View("Login");
        }

    }

When logging-in, after model state validation, claims are added to the identity. After that, cookie is created by using SignIn() method of AuthenticationManager. If there were a database in behind with UserId, claims would be added in this manner:

claims.Add(new Claim(ClaimTypes.NameIdentifier, userId));
claims.Add(new Claim(ClaimTypes.Name, FullName ?? UserName));

Role is checked based on username, but usually, database check can be done. Multiple roles can be added by iterating and adding them as ClaimTypes.Role type. User panel can be seen by both User and Administrator roles, and Admin panel only by Administrator role. Because of that, both roles are redirected to User panel. Claim can be read by using the lines presented above in User panel action:

var claims = ((ClaimsIdentity)User.Identity).Claims;
claims.SingleOrDefault(k => k.Type == ClaimTypes.Role).Value

Request.GetOwinContext().Authentication.SignOut() method is used to log out. It expects multiple authentication types. Add the link to login page in /Home/Index:

@Html.ActionLink("Login", "Login", "Account")

In /Account/Login add the model:

@model ExampleProject.Models.LoginViewModel

and the form (with links to panels – for testing purposes):

@using (Html.BeginForm("Login", "Account", FormMethod.Post))
    {
        @Html.ValidationSummary()
        @Html.TextBoxFor(k => k.Username)<br />
        @Html.PasswordFor(k => k.Password)<br />
        @Html.CheckBoxFor(k => k.RememberMe)<br />
        <input type="submit" value="Login" />
    }
    <br />
    <p>@Html.ActionLink("UserPanel", "UserPanel", "Account")</p>
    <p>@Html.ActionLink("AdminPanel", "AdminPanel", "Account")</p>

In /Account/AdminPanel add output of identity name, link to user panel and logout link:

<h1>Admin panel</h1>
<p>@User.Identity.Name</p>
<p>@Html.ActionLink("User panel", "UserPanel", "Account")</p>
<p>@Html.ActionLink("Logout", "Logout", "Account")</p>

In /Account/UserPanel add output of identity name, link to admin panel and logout link:

<h1>User panel</h1>    
<p>@User.Identity.Name</p>
<p>@Html.ActionLink("Admin panel", "AdminPanel", "Account")</p>
<p>@Html.ActionLink("Logout", "Logout", "Account")</p>

There is also Part 2 of this tutorial.

 

]]>
CSVBuilder using reflection https://pro9ramming.com/csvbuilder-using-reflection/ Thu, 22 Dec 2016 10:11:52 +0000 http://pro9ramming.com/blog/?p=397 Continue reading CSVBuilder using reflection]]> Generating a CSV that can be opened in Excel is a trivial task as long as “Windows ANSI codepage 1252” encoding is used:

Encoding windows1252 = Encoding.GetEncoding(1252);
File.WriteAllBytes(outputFilePath, windows1252.GetBytes(someString));

The CSVBuilder class uses reflection to output a CSV string from a collection (IEnumerable) of POCOs.  Parameter T has to be a class. Default semi-column separator/delimiter is used.

public class CSVBuilder<T> where T: class
    {
        private char _separator;
        public CSVBuilder() : this (';') {}

        public CSVBuilder(char separator)
        {
            _separator = separator;
        }

        private PropertyInfo[] GetProperties()
        {
            return typeof(T).GetProperties().Where(p => Attribute.GetCustomAttribute(p, typeof(NotMappedAttribute)) == null).ToArray();
        }

        private StringBuilder GetHeaders()
        {
            var sb = new StringBuilder();
            sb.AppendLine(string.Format("sep={0}", _separator));

            foreach (var property in GetProperties())
            {
                var descriptionAttribute = Attribute.GetCustomAttribute(property, typeof(DescriptionAttribute)) as DescriptionAttribute;
                var columnHeader = descriptionAttribute == null ? property.Name : descriptionAttribute.Description;
                sb.Append(columnHeader);
                sb.Append(_separator);
            }
            sb.AppendLine();

            return sb;
        } 

        public string GetString(IEnumerable<T> data)
        {
            var sb = GetHeaders();
            foreach (var item in data)
            {
                foreach (var property in GetProperties())
                {
                    sb.Append(property.GetValue(item, null));
                    sb.Append(_separator);
                }
                sb.AppendLine();
            }

            return sb.ToString();
        }

    }

DescriptionAttribute from System.ComponentModel is used to get metadata about headers (specified as [Description(“Header”)]). If Attribute is not present, property name would be used. NotMappedAttribute System.ComponentModel.Schema is used to emphasize that property shouldn’t be mapped.

Class is used in the following way:

var csv = new CSVBuilder<ActualSecurities>();
var someString = csv.GetString(data);

 

]]>
ASP.NET MVC appSettings configuration https://pro9ramming.com/asp-net-mvc-appsettings-configuration/ Wed, 16 Nov 2016 13:39:54 +0000 http://pro9ramming.com/blog/?p=402 If you don’t want to build your application on every configuration change, saving configuration to Web.config is a good solution. WebConfigurationManager class can be used to access this data. Web.config should have these lines:

<configuration>
   <appSettings>
      <add key="configItem" value="configItemValue" />
   </appSettings>
</configuration>

Data can be accessed in the application:

string configItem = System.Web.Configuration.WebConfigurationManager.AppSettings["configItem"];

 

 

]]>
Some C# reflection features https://pro9ramming.com/some-c-sharp-reflection-features/ Sun, 29 May 2016 14:39:03 +0000 http://pro9ramming.com/blog/?p=409 Continue reading Some C# reflection features]]> Mark inherited properties

Sometimes it is needed to list all properties of a class, but having indication if they are inherited or not. That can be checked by checking DeclaringType of a property. If DeclaringType equals to type of class properties are read from, property is not inherited. C# 6.0 features used in the example.

foreach (var item in typeof(MyClass).GetProperties())
{
var inherited = item.DeclaringType == typeof(MyClass) ? "not inherited" : "inherited";
Console.WriteLine($"{item.Name} - {inherited}");
}

 

Get properties that do not have specific attribute

Sometimes certain properties have to be obmited. They can be marked with [NotMapped] attribute from System.ComponentModel.DataAnnotations.Schema namespace.

typeof(SomeType).GetProperties().Where(p => Attribute.GetCustomAttribute(p, typeof(NotMappedAttribute)) == null)

 

Get array properties

Reading array properties can be done by checking PropertyType. There is IsArray indicator in PropertyType which is a property of PropertyInfo class (too many properties :P).

foreach (var item in typeof(MyClass).GetProperties().Where(k=>k.PropertyType.IsArray))
Console.WriteLine(item.Name);

 

]]>
C# 6.0 features wrap up https://pro9ramming.com/c-6-0-features-wrap-up/ Sun, 10 Jan 2016 14:29:23 +0000 http://pro9ramming.com/blog/?p=407 Continue reading C# 6.0 features wrap up]]> It’s been a while since C# 6.0 and CTP3 came up. Here is the code that summarizes all its exciting features in Console application:

class Program
{
        public static string Temp { get; set; } = "TEMP";
        public static string Test => 
 $"{nameof(Temp)} values is: {Temp?.ToLower() ?? "default"}";
        static void Main(string[] args)
        {
            Console.WriteLine(Test);
            Temp = null;
            Console.WriteLine(Test);
            Console.ReadKey();
        }

 }

First one is auto-property initializer which is usually done in constructor. If you leave set initializer, property is read-only for outside class users. Second is Expression bodied property (there are functions/methods too). Any delegate (with the same return type) can be assigned to property or method. String interpolation is used to return formatted string. Inside its declaration, null-conditional operator is used. If Temp property is null, ToLower() method won’t be called. Instead of that, null value would be returned and NullReferenceException won’t be thrown. Already known ?? operator is used to set default value. Output from this code is:

Temp values is: temp

Temp value is: default

]]>