Visual Studio: Bower is Dead Long Live LibMan

rip_bower.pngSo, Bower is dead for Visual Studio.  NPM and WebPack are external tools and overkill if all you really want to do is add a simple open source project like Bootstrap-Datepicker.

As of Visual Studio 2017.7, you can use a Visual Studio tool to get client side libraries.

The goal of this tutorial is to include Bootstrap-Datepicker, a popular javascript open source project.

Step 1: Turn on Library Manager by right clicking the Project and choosing Manage Client-side libraries

libman1.png

A new file called LibMan.json is added. If you open it you’ll see this:

libman2.png

By default LibMan.json uses the content provider “CDNJS” to provide the JS. Other providers are available. Remember this isn’t a CDN, it’s just where to download the JS from.

Let’s add a defaultDestination for our packages:

libman3.png

Step 2: To add a library, go to cdnjs.com and find the package, for example:

https://cdnjs.com/libraries/bootstrap-datepicker

We now know the name of the package “bootstrap-datepicker”.  Add that and use a @ at the end to get intellisence for the version number:

libman4.png

Save the file, then right click libman.json and choose Enable Restore on Build to have a NuGet package added which will cause MSBuild to download JS packages.

Build the solution and you’ll see bootstrap-datepicker.js added.

libman5.png


That’s the fastest way to get started, here’s some more documentation for finer control.

 

 

Advertisements

ASP.NET Core 2: Using SQLite as a light weight database

SQLite370.svg.pngAzure is a great place to store your data of any size, but sometimes that may not be possible for a number of reasons. In this article I’ll show you how to use Microsoft Entity Framework Core (EF) and SQLite to create and store a small amount of data.

This code is a bare-bones example. It doesn’t include important features like error handling or DI.

Note: There is no database file. EF Core will create the SQLite database file for you.

Step 1: Create any simple ASP.NET Core site via the (File | New) menu

Step 2: Add these NuGet packages

  1. Microsoft.EntityFrameworkCore
  2. Microsoft.EntityFrameworkCore.Sqlite
  3. Microsoft.EntityFrameworkCore.Sqlite.Core

Step 3: DbContext

All of the magic takes place in a single simple data class. Add this to your solution:

public class SimpleDataStorageDbContext
{
    public SimpleDataStorage(){}
 
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        //Set the filename of the database to be created
        optionsBuilder.UseSqlite("Data Source=db.sqlite");
    }
 
    public DbSet<Cat> Cats { getset; }
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
 
        //Define the Table(s) and References to be created automatically
        modelBuilder.Entity<Cat>(b =>
        {
            b.HasKey(e => e.Id);
            b.Property(e => e.Id).ValueGeneratedOnAdd();
            b.Property(e => e.Name).IsRequired().HasMaxLength(255);
            b.ToTable("Cats");
        });
    }
}

What’s very interesting here is that the database doesn’t exist, the class SimpleDataStorage tells EF how and where to create it.

Step 4: Create the database and tables in Startup.cs

public class Startup
{
   public Startup()
    {
        using (var client = new SimpleDataStorage())
        {
            //Create the database file at a path defined in SimpleDataStorage
            client.Database.EnsureCreated();
            //Create the database tables defined in SimpleDataStorage
            client.Database.Migrate();
        }
    }

Step 5: Add Cats to the database!

We can now access the database anywhere in code

public IActionResult Index(SimpleDataStorage db)
{
    for (int i = 0; i < 1000; i++)
    {
        db.Cats.Add(new Cat() {Name = "Caty McCat: " + i}); 
    }
    db.SaveChanges(true);
    return View();
}


Resources: A good SQLite database editor

 

ASP.NET Core 2: Custom Authentication Part 2

Browser-Cookies.jpgIn Part 1 we asked ASP.NET Core to use Cookie based authentication and to include the authentication engine into the request pipeline. In this next simple example, we’ll log the user in and verify they are logged in. ASP.NET Core has a built-in user system, however in these posts I’m assuming you can’t use that and have to use an external user database or web service.

To keep this as narrowly focused as possible, I am skipping the User Manager features like looking up the user in a database and comparing password hashes. If you need a good UserManager.cs file for ASP.NET Core outside of the built-in one, here’s a good one.

In the HomeController.cs add this function. It’ll handle a complete Login:

[AllowAnonymous]
public async Task<IActionResult> SignIn()
{
 
    //Create a plain C# Class
    //In real-life, get this from a database after verifying the username and password
    MyUser user = new MyUser()
    {
        Id = 1,
        Name = "Fred Fish"
    };
 
    //Add the ID of the user and the name to a collection of Claims
    List<Claim> claims = new List<Claim>
    {
        new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
        new Claim(ClaimTypes.Name, user.Name)
    };
 
    //Create the principal user from the claims
    ClaimsIdentity identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
    ClaimsPrincipal principal = new ClaimsPrincipal(identity);
    AuthenticationProperties authenticationProperties = new AuthenticationProperties() {IsPersistent = false};
 
    //Ask MVC to create the auth cookie and store it
    await this.HttpContext
            .SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, 
             principal, authenticationProperties);
 
 
    //DONE!
    return this.RedirectToAction("Index");
}

Let’s break this down now:

We first need a User class, this can be a plain old C# object. There is no magic here.

public class MyUser
{
    public int Id { getset; }
    public string Name { getset; }
}

Next we need to add information about the user we just made to a collection of Claims. Claims can contain groups or roles or names and ids. Think of it as the bucket of certified security information about a user.

List<Claim> claims = new List<Claim>
{
    new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
    new Claim(ClaimTypes.Name, user.Name)
};

We now wrap up all the claims and info about the user into a Principal:

ClaimsIdentity identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
AuthenticationProperties authenticationProperties = new AuthenticationProperties() { IsPersistent = false };
ClaimsPrincipal principal = new ClaimsPrincipal(identity);

And finally, take the Principal and ask the HttpContext to store it in a cookie:

await this.HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal, authenticationProperties);

We are now logged in. To check, in the post-login View, have a look at the User

@if (this.User.Identity.IsAuthenticated)
{
    <b>Authenticated!</b>
} 

Done!

 

ASP.NET Core 2: Custom Authentication Part 1

ASP.NET Core 2 comes with easy to use out-of-the-box authentication. In Visual Studio 2017 you can create fully functioning projects via the File | New menu.

These next few tutorials will focus on doing a custom implementation. Perhaps your organization wishes to authenticate against a customer database, or even a web service. I’ll show you how to implement that all using the beautiful ASP.NET Core 2 authentication infrastructure.

Step 1: Create a new blank project, no authentication

For this tutorial we’ll use “.NET Framework” as we’ll be hosting in IIS

custom auth.png

Step 2: Add the NuGet package Microsoft.AspNetCore.Authentication.Cookies

Step 3: In Startup.cs add Cookie customization for the authentication cookie:

public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
        .AddCookie(options =>
            {
                options.ExpireTimeSpan = TimeSpan.FromDays(7);
                options.LoginPath = "/Account/CustomLogin";
                options.Cookie.Name = "MyAuthCookieName";
            }
        );
 
    services.AddMvc();
}

Step 4: In Startup.cs ‘s Configure method add UseAuthentication()

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseBrowserLink();
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
    }
 
    app.UseAuthentication();  //IMPORTANT
    app.UseStaticFiles();

 

 

In the cookie customization, you can change many features like the login page from the default “/Account/Login” and the name of the Cookie. The defaults are sensible however.

In Part 2 we’ll add a UserManager class which will handle authentication.

This post is possible based on the excellent work at this site.

Creating PDFs from Word and Excel Documents on IIS. For Free.

pdf.pngConverting a Microsoft Word or Excel file to a PDF is usually an expensive task. Commercial Services exist, but there are no free options. As well, you may not be able to use a service as your documents may be confidential and can’t be sent over national borders.

There is a simple solution that is free, secure and easy. Really.

Note: You will need full control over your IIS server to use this toolset

Summary: How we do it

Your web site will save the Word or Excel file onto the server’s file system. A Windows Service will watch that folder then when a document appears will send it off to the open source Libre Office and have it create the PDF via a headless call. Your web site will then pick up the PDF from the same folder and send it along.

Let’s do it!


Step 1: IIS Server Setup. You’ll need total control of the server.

  1. Create a file folder on the server that your web site’s IIS Application pool has read-write access to. For example c:\FileDrop
  2. Install LibreOffice on the server. Default settings.

Step 2: Web Site

Your web site will need to deposit the Word or Excel file into c:\FileDrop. You’ll need to handle that code, but it’s fairly simple. If you need help, Google it.


Step 3: The Windows Service

Create a new Console App. This will be your Windows Service.

Change Program.cs to this:

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.ServiceProcess;
 
namespace PdfService
{
    internal class Program : ServiceBase
    {
        private static void Main(string[] args)
        {
            ServiceBase.Run(new Program());
        }
 
        public Program()
        {
            this.ServiceName = "DataSystem PDF";
        }
 
        private FileSystemWatcher _watch;
 
        protected override void OnStart(string[] args)
        {
            base.OnStart(args);
            try
            {
                var path = System.Configuration.ConfigurationManager.AppSettings["PdfPath"];
                
                Trace.WriteLine("PDF: Using Path=" + path);
                if (!Directory.Exists(path))
                {
                    Trace.WriteLine("PDF: Creating " + path);
                    Directory.CreateDirectory(path);
                }
 
                _watch = new FileSystemWatcher(System.Configuration.ConfigurationManager.AppSettings["PdfPath"]);
                Trace.WriteLine("PDF: Started File Watcher");
                _watch.Created += watch_Created;
                _watch.EnableRaisingEvents = true;
 
            }
            catch (Exception e)
            {
                Trace.WriteLine("PDF: Error " + e.Message); 
            }
        }
 
        private void watch_Created(object sender, FileSystemEventArgs e)
        {
            Trace.WriteLine("PDF: WATCH: " + e.FullPath);
            if (Path.GetExtension(e.FullPath) == ".xlsx" || Path.GetExtension(e.FullPath) == ".docx")
            {
 
                Trace.WriteLine("PDF: Processing " + e.FullPath);
                string exePdf = System.Configuration.ConfigurationManager.AppSettings["PdfExe"];
                string param = System.Configuration.ConfigurationManager.AppSettings["PdfParameters"];
 
                var pdfProcess = new Process();
                pdfProcess.StartInfo.FileName = exePdf;
                pdfProcess.StartInfo.Arguments = param + \"" + e.FullPath + "\"";
                pdfProcess.StartInfo.WorkingDirectory = Path.GetDirectoryName(e.FullPath); //!!!!This is really important!!!!!
                pdfProcess.Start();
                pdfProcess.WaitForExit(25000);
                if (!pdfProcess.HasExited)
                    pdfProcess.Kill();
            }
        }
 
        protected override void OnStop()
        {
            base.OnStop();
 
            _watch = null;
        }
    }
}

Add a new class called PDFServiceInstaller.cs and change the code to this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration.Install;
using System.ComponentModel;
using System.ServiceProcess;
 
namespace PdfService
{
  [RunInstaller(true)]
  public class PDFServiceInstaller : Installer
  {
      private ServiceInstaller serviceInstaller;
 
      public PDFServiceInstaller()
    {
      var processInstaller = new ServiceProcessInstaller();
        serviceInstaller = new ServiceInstaller();
 
      //set the privileges
      processInstaller.Account = ServiceAccount.LocalSystem;
 
      serviceInstaller.DisplayName = "DataSystem PDF";
      serviceInstaller.StartType = ServiceStartMode.Automatic;
 
      //must be the same as what was set in Program's constructor
      serviceInstaller.ServiceName = "DataSystem PDF";
 
      this.AfterInstall += new InstallEventHandler(ServiceInstaller_AfterInstall);
 
      this.Installers.Add(processInstaller);
      this.Installers.Add(serviceInstaller);
    }
 
      void ServiceInstaller_AfterInstall(object sender, InstallEventArgs e)
      {
          using (ServiceController sc = new ServiceController(serviceInstaller.ServiceName))
          {
              sc.Start();
          }
      }
  }
}

Edit the App.Config and change it to this. Make any changes to paths you need.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <appSettings>
    <add key="PdfExe" value="C:\Program Files (x86)\LibreOffice 6\program\soffice.exe"/>
    <add key="PdfParameters" value=" -norestore -nofirststartwizard -nologo -headless -convert-to pdf "/>
    <add key="PdfPath" value="c:\FileDrop"/>
  </appSettings>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2"/>
  </startup>
</configuration>

Step 4: Installing the Service

Compile the PdfService and place it on your IIS server, in our example c:\PdfService. Here’s how you install it.

  1. Run the command prompt as ADMIN
  2. cd to -> C:\Windows\Microsoft.NET\Framework64\v4.0.30319
  3. Run InstallUtil.exe C:\PdfService\PdfService.exe

To uninstall
InstallUtil.exe -u C:\PdfService\PDFService.exe

To watch DEBUG info, Run DebugViewer from Sys Internals and enable Global Win32 watching in DebugViewer


Step 5: Start the service via the management tool Services.msc. Simple right click “DataSystem PDF”


Conclusion

Now that the service is running, you can test it by just dropping a Word or Excel file into the folder. A PDF should appear in 10-20 seconds depending on size and your server’s power.

 

 

ASP.NET Core 2: Adding an Authorization Policy

In ASP.NET Core, an Authorization Policy is simply some code that says “Are you allowed to do something” In this rather contrived example, we’re going to only allow access to a Controller’s Action if a weather service indicates it’s raining. Why not 🙂

Step 1: Create a new solution that has some kind of authentication. Doesn’t matter what kind.

Authentication aspnet core.png

Step 2: Create a new AuthorizationPolicyBuilder extension class so we can add the Policy in our Startup.cs in step 3 next.

public static class WeatherAuthorizationPolicy
{
    public static string Name => "IsRaining";
    public static void Build(AuthorizationPolicyBuilder builder)
    {
        builder.RequireAssertion(context => IsRaining(context.User));
    }
    public static bool IsRaining(ClaimsPrincipal user)
    {
        //Todo access a weather service here.
        //return GetWeatherForUser(user);
        return true;
    }
 }

Step 3: Add the Policy in your Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthorization(options =>
    {
        options.AddPolicy(WeatherAuthorizationPolicy.Name, 
                      WeatherAuthorizationPolicy.Build);
    });

Step 4: Add an Authorize attribute to an Action

[Authorize("IsRaining")]
public IActionResult RainInSpain()
{ 
    return View();
}

That’s it.


BONUS

I would recommend creating a Authorize Attribute so that you don’t have the magic string “IsRaining” all over the place. Excluded for simplicity.

public class AuthorizeIsRaining : AuthorizeAttribute
{
    public AuthorizeIsRaining()
           :base(WeatherAuthorizationPolicy.Name) {}
}

You can also call this policy in code by using an injected IAuthorizationService:

public MyNiceController(IAuthorizationService  authorizationService)
{
    _authorizationService = authorizationService;
}
public async Task CheckRain()
{
    var result = await _authorizationService
                .AuthorizeAsync(User, WeatherAuthorizationPolicy.Name);
     if (result.Succeeded)
        { .... }
}

 

ASP.NET Core 2: LLBL + Entity Framework Core

logo

LLBL is an awesome ORM that’s been around for a long time, is actively worked on, has amazing tech support and produces rock solid code. I don’t own stocks, I just love the tool.

This article assumes you have a little bit of experience with LLBL. We’ll be using a new Database and the Database-first design, but you can change that to what suits you.

I’m skipping certain best practices, like using a repository pattern,  for the sake of simplicity.

Step 1: Create a database with a login and at least 1 table.

FincnaceToo.png

Step 2: Create a New LLBL Project for Entity Framework Core v2 and save it in the ASP.NET Core solution folder. Database first

create llbl.png

Step 3: Using the dialog that appears, connect to your database and choose the table(s) you’d like to add

llbl connect.png

Step 4: Add the Tables as Entities

reverse LLBL.png

Step 5: Press the Generate Code button and then the Edit Selected Task Specifics. Change the Destination root folder to .\LLBL

llbl folder.png

Step 6: Press the Perform Tasks button to generate the LLBL projects. Close LLBL.

Step 7: Open Visual Studio 2017 and the ASP.NET Core project. Add the 2 new projects LLBL just created

Step 8: Add a reference to the LLBL projects to your ASP.NET Core main project

Step 9: Add these NuGet Packages to the LLBL Persistence project:

  1. Microsoft.EntityFrameworkCore
  2. Microsoft.EntityFrameworkCore.Relational

Step 10: To the LLBLPersistence project’s DataContext class add a partial file and add this new constructor so ASP.NET Core can pass options to it.

	public partial class FinanceTooDataContext 
	{
	    public FinanceTooDataContext(DbContextOptions<FinanceTooDataContext> options)
                  :base(options)
	    {}

Step 11: Add the LLBL DataContext options to the ConfigureServices of Startup.cs

public void ConfigureServices(IServiceCollection services)
{
   services.AddDbContext<FinanceTooDataContext>(options => options
      .UseSqlServer(Configuration.GetConnectionString("LLBLConnection")));
 

Step 12: Add LLBLConnection to appsettings.json

{
  "ConnectionStrings": {
    "LLBLConnection""data source=.\\sqlexpress;initial catalog=FinanceToo;User ID=MyUserName;Password=password;persist security info=False;packet size=4096"
  },

Step 13: Access the data context in a controller! Done

public class HomeController : Controller
{
    public HomeController(FinanceTooDataContext context)
    {