Posts by John

Software developer, lately specialising in Full Stack Web Development using c#, ASP.Net WebAPI 2, and Angular.

Angular 7 Guard Service and Unit Tests

I’m fairly new to Angular 7, (or indeed Angular 2+, having spent the last couple of years doing AngularJS development.

So, in Angular, I’ve created a Guard service which all made sense and was fairly straightforward, however, I found that writing the unit tests was much harder, finding that none of the examples on StackOverflow or on other sites seemed to work with Angular 7.

The code is here:

The guard service

The guard will check whether a user is logged in, and if a claim is passed in, will check whether the user has the claim.

The checkLoggedIn method, first checks the authentication service to see if the user is logged in. If the user is logged in it simply returns true. If the user is not logged in, it saves the desired URL to the authentication service to allow for redirection once the user is logged in, then it navigates to the login page.

The checkClaim method checks whether the currentUser object in the authorisation service has the claim in the claims list.

The unit test

First, we set up a mock ActivedRouteSnapshot and a mock RouterStateSnapshot. In the MockActivatedRouteSnapshot we have the data object that will hold the expectedClaim.


Then we set up the describe block, providing the guard and the ActivedRouteSnapshot.

Logged Out Test

Next the first test, checking that you can’t get to a route that requires authentication if you’re logged out.

So in this test, we’re setting a mock authentication service, that returns false, from checkLoggedIn, and also with the spyOnProperty, we’re telling it to return the expectedClaim = ‘policy’ in the data value of the route.

Logged In Test

Next, checking whether you can get to a route if you’re logged in:

In this test, w’re returning true for the checkLoggedin method, but not requiring a claim.

No claim test

Next, checking that you can’t get to a route that requires a claim you don’t have.

In this test, we’re setting up the authentication service to return true for logged in, and setting the route to require the expectedClaim of ‘policy’, but we’re not adding the that claim to the user.

Valid claim test

Finally, check that you can get to a route that you have a valid claim for.

In this test, we’ve set up the currentUser object in the authentication service to have a claims property, that contains a claim of ‘policy’.

Advertisements
NuGet logo

Nuget Package restore issues

After upgrading Nuget on VS2013, we’ve started hitting an issue where Nuget won’t restore packages. We get error messages similar to this:

Error 21 Could not find a part of the path 'C:\Dev\YourProject\ \packages\Microsoft.AspNet.WebApi.Core.5.2.3'.

I’ve found out that there is a change to the way Nuget picks up files. To get it to work you need to edit the file NuGet.targets changing the line:

<RestoreCommand>$(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)" $(NonInteractiveSwitch) $(RequireConsentSwitch) -solutionDir $(PaddedSolutionDir)</RestoreCommand>

To:

<RestoreCommand>$(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)" $(NonInteractiveSwitch) $(RequireConsentSwitch) -solutionDir $(SolutionDir)\</RestoreCommand>

This sorts the issue.

Adding Swagger to a C# WebApi

About Swagger

Swagger (https://swagger.io/) is a free open-source tool that enables easy documentation and testing of APIs. It is language agnostic.

Swashbuckle (https://github.com/domaindrivendev/Swashbuckle) is a .Net specific tool that adds Swagger to a .Net Web Api.

Installation

Install from Nuget

Install-Package Swashbuckle

Register Swagger

The Swashbuckle install should create a SwaggerConfig.cs file in the App_start Directory. This will allow you to configure Swagger in various ways.

Enable XML document generation

Open the project properties for your WebApi project, select the build tab and change the setting below:

Annotation 2019-02-20 111835

Update swagger config to use the XML comments

In the SwaggerConfig.cs file uncomment the line below:

c.IncludeXmlComments(GetXmlCommentsPath());

and add the method :

private static string GetXmlCommentsPath()
{
   var filepath = System.String.Format(@"{0}\bin\documentation.XML", System.AppDomain.CurrentDomain.BaseDirectory);
   return filepath;
}

Adding XML comments to code

On your controller and individual endpoints add the /// triple slash comments, for example

///
/// Search returns a paged, filterd list of events
///

///filters for the search ///number of entries to return per page ///page number to return ///name of column to sort by ///direction of sort /// A list of Events /// Success /// No Data Found /// Internal Server Error [Route(“Search”)] [HttpGet] [SwaggerResponse(200)] [ResponseType(typeof(IQueryable))] public IHttpActionResult GetList([FromUri] EventArguments parameters, [FromUri] int pageSize = 25, [FromUri] int pageNumber = 1, [FromUri] string sortColumn = “Id”, [FromUri] bool sortForward = true) { … }

 

Creating a multi project solution in VS2013

Ok, so this is probably a bit out of date as VS2019 is due out soon, but one of my clients is still using VS2013 as their main IDE, as they can’t update one of their projects for various reasons.

The project I’m working on them with is an AngularJS front-end to a micro-services architecture with around 20 micro-services. Creating a new service can be a bit of a pain, especially keeping them in line with internal standards, therefore I created a multi-project template to create a new service, and it does it in around 5 minutes from scratch to a working WebApi service.

I followed the guide here: https://docs.microsoft.com/en-us/visualstudio/ide/how-to-create-multi-project-templates?view=vs-2017, but there are a couple of gotchas.

    1. Take a working solution and copy it into a new folder, remember to remove source control bindings.
      folder structure
    2. Strip the solution to a bare bones solution that provides a working example of what you want do do. For this project, I have one data model, one DTO, one repository & interface, one service and interface and one WebAPI controller with one endpoint.solution Explorer
    3. Check that it still runs.
    4. Clean the solution, delete contents of bin and obj directories  in each project.
    5. In the File menu choose Export Template, and export each project. These will be exported to a folder like C:\Users\XXX\Documents\Visual Studio 2013\My Exported Templates
      Export Template Menu Item
      Export Template Page 1

      Export Template Page 2
    6. Copy each of them into the respective project folders and rename them to match the project name.
      Project contents
    7. Create a root.vsTemplate file – Refer to the guide for more info on this.
    8. Select the project folder and the root.vsTemplate (exclude the solution file, packages folder and .nuget folder) and right click –> Send to –>Compressed (zip) file.
    9. Rename the zip file and copy it to C:\Users\XXX\Documents\Visual Studio 2013\Templates\ProjectTemplates.
    10. Open a new copy of Visual Studio and select File\Create a new project, search for your template and create a new project.
    11. You should have a fully working WebApi.
    12. You can now add the package to a VSIX project and make that available for everyone to use.

 

 

Setting up Development Configurations in Visual Studio

Working in a medium sized development team, we have found a source of frustration is when one developer checks in a change to the web.config that they’ve been using for testing that affects everyone else.

While looking at ways to stop this we discovered that you can have the web.config load settings in from other files.

ConfigSource

Some sections of the web.config allow you to add a ConfigSource attribute. for instance the connectionStrings section.  Before we would have several connectionStrings sections, one for each environment, but commented out.

Now, by adding the ConfigSource attribute, we can save the different connectionStrings sections to separate files, e.g. Dev, Dev2, etc., and simply change which one we point to. It’s much cleaner and more readable.

 <connectionStrings configSource="ConfigFiles\Dev_ConnectionStrings.config" />

AppSettings

AppSettings doesn’t allow you to use the ConfigSource, however, it does allow you to use the file attribute. The difference is that the file attribute brings in settings from another file that override the current settings.

<appSettings file="LocalSettings\DeveloperAppSettings.config">
   …
   …
</appSettings>

Also, the file is optional, so that if it doesn’t exist, the project will still run.

Example web.config extract

<connectionStrings configSource="ConfigFiles\DEV_ConnectionStrings.config" /> 
<appSettings file="LocalSettings\DeveloperAppSettings.config">
   <add key=”settingToOverride” value=”1”/> 
</appSettings>

ConnectionStrings.config

<connectionStrings>
  <add name="Database1Connection" connectionString="data source=Server1;initial catalog=Database1;user id=Database1User;password=password;" providerName="System.Data.SqlClient" />
  <add name="Database2Connection" connectionString="data source=Server2;initial catalog=Database2;user id=Database2User;password=password;MultipleActiveResultSets=True;App=EntityFramework" providerName="System.Data.SqlClient" />
</connectionStrings>

DeveloperAppSettings.Config

<appSettings>
   <add key=”settingToOverride” value=”2”/>
</appSettings>

Excluding the local files from TFS

First, the solution or project should have a “.tfignore” file created.

Example .tfignore file

###############################
# Ignore developer config files
\LocalSettings
# ignore logs
\logs
###############################
  • Check this file in.
  • Close and reopen the solution – This is important, as it seems to initialise the .tfIgnore.
  • Create the folder LocalSettings
  • Add the ConnectionStrings.config file
  • Add the DeveloperAppSettings.config file
    • Under Properties, set the Build Action to NONE
  • In Source Control Explorer, undo the changes to the DeveloperAppSettings.config file.

See also:

NuGet logo

Automatically building NuGet packages for your project–updated

As a follow on from my last post on this subject, I’ve come across a simplified way of doing this.

  1. Build your .nuspec file as usual. (use NuGet spec in a CMD window in the project folder to generate the basic file).
  2. Update the AssemblyInfo.cs file with a description and a company, or the NuGet build will throw errors.
  3. Edit the project file:

Add these two lines to the first <PropertyGroup>:

<RestorePackages>true</RestorePackages>
<BuildPackage>true</BuildPackage>

Add these lines at the end for the file:

<ImportProject=”$(SolutionDir)\.nuget\NuGet.targets”Condition=”Exists(‘$(SolutionDir)\.nuget\NuGet.targets’)”/><TargetName=”EnsureNuGetPackageBuildImports”BeforeTargets=”PrepareForBuild”>    <PropertyGroup>
      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
      </ErrorText>
   </PropertyGroup>
      <ErrorCondition=”!Exists(‘$(SolutionDir)\.nuget\NuGet.targets’)”Text=”$([System.String]::Format(‘$(ErrorText)’, ‘$(SolutionDir)\.nuget\NuGet.targets’))”/></Target>

SQL Server: Finding a column in multiple databases.

My client has many instances of the same database in various versions. The version I’m developing against is missing a field expected by a c# class, and I can’t find a script to create the column.

I came up with the following SQL Server query to allow me to search all the instances of the database to find one that contained the field.

EXEC sp_MSforeachdb 
 'SELECT ''Found in ?''
 FROM sys.columns 
 WHERE Name = N''FieldName''
 AND Object_ID = Object_ID(N''TableName'')'

Replace the field name and the table name with the values you’re looking for and it will search all the databases on the server for  a match.

Launching .EXE applications from a browser

My client has an Angular intranet portal for their main c# WinForm application. They have a requirement to launch the main application from the portal website.

There is a fairly easy way to go about this in Windows although it does require adding an entry to the registry, to set up a URI Scheme. Here is an example to load notepad.exe

HKEY_CLASSES_ROOT
   jmNotepad
      (Default) = "URL:jmNotepad Protocol"
      URL Protocol = ""
      DefaultIcon
         (Default) = "notepad.exe,1"
      shell
         open
            command
               (Default) = "C:\windows\notepad.exe"

In the web page, add a simple link:

<a href="jmNotepad:">Launch Notepad</a>

The first time it’s launched you get a warning, which you can click to ignore subsequently.