.
Anmeldung | Registrieren | Hilfe

.NET-Blogs Archiv März 2017

Visual Studio 2017 Launch bei der .NET User Group Koblenz

22.03.2017 13:39:39 | Andre Kraemer

Am 7. März 2017 veröffentliche Microsoft pünktlich zum 20. Geburtstag von Visual Studio die neue Version 2017.

Bei der .NET User Group Koblenz werden wir aus diesem Anlass am 24. März 2017 um 19:00 Uhr ein Treffen abhalten, bei dem Eric Berres und ich die wichtigsten neuen Features vorstellen werden, mit denen Entwickler noch produktiver werden.

Unter anderem werden wir folgendes besprechen:

  • Visual Studio 2017 Installer / Workloads
  • Schnellerer Start von Visual Studio 2017 dank Lightweight Solution Load
  • Neue Refactorings in Visual Studio
  • ASP.NET Core und Docker
  • Live Unit Testing in Visual Studio 2017
  • Xamarin in Visual Studio 2017

Visual Studio 2017 Launch Event T-Shirts

Für alle Microsoft MSDN Abonnenten gibt es übrigens auch noch ein kleines Geschenk seitens Microsoft: Ein Visual Studio 2017 Geburtstags-T-Shirt. Sollten wir nicht genug Shirts für alle Teilnehmer haben, dann werden diese nach dem Prinzip: First-Come, First-Serve ausgeteilt.

Visual Studio 2017 Launch Event T-Shirts

Weitere Details gibt es auf der Webseite der .NET User Group Koblenz

Integrate Meetup events on your website

12.03.2017 18:00:00 | Jürgen Gutsch

This is a guest post, written by Olivier Giss about integrating Meetup events on your website. Olivier is working as a web developer at algacom AG in Basel and also one of the leads of the .NET User Group Nordwest-Schweiz


For two years, I am leading the .NET User Group Nordwest-Schweiz with Jürgen Gutsch that owns this nice blog. After a year, we decided also to use Meetup to get more participants.

Understanding the problem

But with each added platform where we post our events, we increased the workload to keep it all up to date. Jürgen had the great idea to read the Meetup events and list them on our own website to lower the work.

This is exactly what I want to show you.

The Meetup API

Before we start coding we should understand how the API of Meetup is working and what it does offer. The API of Meetup is well documented and supports a lot of data. What we want is to get a list of upcoming events for our meetup group and display it on the website without to be authenticated on meetup.com.

For our goal, we need the following meetup API method:

GET https://api.meetup.com/:urlname/events

The parameter “:urlname” is the meetup group name. In the request body we could sort, filter and control paging what we don’t need. If we would execute that query, you get an authorization error.

However, we don’t want that the user must be authenticated to get the events. To get it to work we need to use a JSONP request.

Let’s getting it done

The simplest way doing a JSONP request is using jQuery:

$.ajax({
  url: "https://api.meetup.com/Basel-NET-User-Group/events",
  jsonp: "callback",
  dataType: "jsonp",
  data: {
    format: "json"
  },
  success: function(response) {
    var events = response.data;
  }
});

Be aware: JSONP has some security implications. As JSONP is really JavaScript, it can do everything that is possible in the context. You need to trust the provider of the JSONP data!

After that call, we are getting the data from the Meetup API which can be used with simple data binding to display it on our website. You can choose any kind of MV* JS framework to do that. I used AngularJS.

<div class="row" ng-repeat="model in vm.Events track by model.Id" ng-cloak>
  <a href="" target="_blank" title="Öffnen auf meetup.com"><h3></h3></a>
  <label>Datum und Uhrzeit</label>
  <p></p>
  <label>Description</label>
  <div ng-bind-html="model.Description"></div>
  <label>Ort</label>
  <p></p>
</div>

As you can see everything is One-Way bound because the data is never changed. The “ng-bind-html” binds HTML content from the meetup event description.

The Angular controller is simple, it uses the "$sce” service to ensure that the provided HTML content from the meetup API is marked as secure. When we change a model outside of angular, we must notify our changes with “vm.scope.$apply()”.

(function () {
  var module = angular.module('app', []);

  module.controller('MeetupEventsController', ['$scope', '$sce', MeetupEventsController]);

  MeetupEventsController.$inject = ['$scope', '$sce'];

  function MeetupEventsController($scope, $sce) {

    var vm = this;
    vm.Events = [];
    vm.scope = $scope;
    vm.loaded = false;

    vm.Refresh = function() {
      $.ajax({
        url: "https://api.meetup.com/Basel-NET-User-Group/events",
        jsonp: "callback",
        dataType: "jsonp",
        data: {
          format: "json"
        },
        success: function(response) {
          var events = response.data;

          for (var i = 0; i < events.length; i++) {
            var item = events[i];

            var eventItem = {
              Id: i,
              DisplayName: item.name,
              Description: $sce.trustAsHtml(item.description),
              Location: item.venue.name + " " + item.venue.address_1 + " " + item.venue.city,
              Time: new Date(item.time).toLocaleString(),
              Link :item.link,
            };
            vm.Events.push(eventItem)
          }
          vm.loaded = true;
          vm.scope.$apply();
        }
      });
    };
    function activate() {
      vm.Refresh();
    };
    activate();
  };
})();

Finally, we are finish. Not that complicated, right? Feel free to ask question or share your experience.


Just visit the website of the .NET User Group Nordwest-Schweiz to see the Meetup integration in action.

Using dependency injection in multiple .NET Core projects

05.03.2017 17:00:00 | Jürgen Gutsch

One of my last post was about Dependency Injection (DI) in .NET Core Console Applications. Some days after that post was published, I got a question about how to use the IServiceCollection in multiple projects. In this post I'm going to try to explain, how to use the IServiceCollection in a Solution with more projects.

Setup

To demonstrate that, I created a Solutions with two .NET Core Console apps and two .NET Standard libraries. One of the console apps uses two of the libraries and the other one is just using on. Each library provides some services which need to be registered to the DI container. Also the console apps provide some services to add.

We now have four projects like this:

  • DiDemo.SmallClient
    • .NET Core Console app
    • includes a WriteSimpleDataService
    • references DiDemo.CsvFileConnector
  • DiDemo.BigClient
    • .NET Core Console app
    • includes a WriteExtendedDataService
    • includes a NormalizedDataService
    • references DiDemo.SqlDatabaseConnector
    • references DiDemo.CsvFileConnector
  • DiDemo.SqlDatabaseConnector
    • .NET Standard library
    • includes a SqlDataService
    • includes a SqlDataProvider used by the service
  • DiDemo.CsvFileConnector
    • .NET Standard library
    • includes a CsvDataService

BTW: Since one of the latest updates the "Class Libraries (.NET Standard)" project disappeared from the ".NET Core" node in the "Add New Project" dialogue and the "Class Library (.NET Core)" is back again. The "Class Libraries (.NET Standard)" is now in the ".NET Standard" node under the "Visual C#" node.

In the most cases it doesn't really makes sense to create a .NET Core class library. The difference here is, that the Class Library (.NET Core) has some .NET Core related references. They targeting the netcoreapp1.x instead of the netstandard1.x. This means they have a lot of references, which are not needed in a class library in the most cases, e. g. the Libuv and the .NET Core runtime.

The WriteExtendedDataService uses a INormalizedDataService to get the data and writes it to the console. The NormalizedDataService fetches the data from the CsvDataService and from the SqlDataService and normalize it, to make it usable in the WriteExtendedDataService.

The WriteSimpleDataService uses only the ICsvDataService and writes the data out to the console.

Setup the DI container

Let's setup the DI container for the SmallClient app. Currently it looks like this:

var services = new ServiceCollection();
services.AddTransient<IWriteSimpleDataService, WriteSimpleDataService>();
services.AddTransient<ICsvDataService, CsvDataService>();

var provider = services.BuildServiceProvider();

var writer = provider.GetService<IWriteSimpleDataService>();
writer.write();

That doesn't really look wrong, but what happens if the app grows and gets a lot more services to add to the DI container? The CsvDataService is not in the app directly, but it is in the separate library. Usually I don't want to map all the services of the external library. I just want to use the library and I don't want to know anything about the internal stuff. This is why we should set-up the mapping for the DI container also in the external library.

Let's plug things together

The .NET Standard libraries should reference the Microsoft.Extensions.DependencyInjection.Abstractions to get the IServiceCollection interface. Now we can create a public static class called IServiceCollectionExtensions to create an extension method to work in the IServiceCollection:

public static class IServiceCollectionExtension
{
  public static IServiceCollection AddCsvFileConnector(this IServiceCollection services)
  {
    services.AddTransient<ICsvDataService, CsvDataService>();
    return services;
  }
}

Inside this method we do all the mappings from the interfaces to the concreate classes or all the other registrations to the DI container. Let's do the same to encapsulate all the services inside the SmallClient app and to keep the program.cs as small as possible:

public static class IServiceCollectionExtension
{
  public static IServiceCollection AddInternalServices(this IServiceCollection services)
  {
    services.AddTransient<IWriteSimpleDataService, WriteSimpleDataService>();
    return services;
  }
}

We can now use this methods in the program.cs of the SmallClient app to plug all that stuff together:

var services = new ServiceCollection();
services.AddInternalServices();
services.AddCsvFileConnector();

var provider = services.BuildServiceProvider();

var writer = provider.GetService<IWriteSimpleDataService>();
writer.write();

It looks much cleaner now. Maybe you remember the AddSomething methods? Exacctly, this is the same way, it is done in ASP.NET Core with e. g. the services.AddMvc() method.

We now need to do the same thing for the BigClient app and the SqlDatabaseConnector library. At first let's create the mapping for the SqlDatbaseConnector:

public static class IServiceCollectionExtension
{
  public static IServiceCollection AddSqlDatabaseConnector(this IServiceCollection services)
  {
    services.AddTransient<ISqlDataService, SqlDataService>();
    services.AddTransient<ISqlDataProvider, SqlDataProvider>();
    return services;
  }
}

We also need to create a extension method for the internal services:

public static class IServiceCollectionExtension
{
  public static IServiceCollection AddInternalServices(this IServiceCollection services)
  {
    services.AddTransient<IWriteExtendedDataService, WriteExtendedDataService>();
    services.AddTransient<INormalizedDataService, NormalizedDataService>();
    return services;
  }
}

Now let's plug that stuff together in the BigClient App:

var services = new ServiceCollection();
services.AddInternalServices();
services.AddCsvFileConnector();
services.AddSqlDatabaseConnector();

var provider = services.BuildServiceProvider();

var writer = provider.GetService<IWriteExtendedDataService>();
writer.write();

As you can see, the BigClient app uses the already existing services.AddCsvFileConnector() method.

Does it really work?

It does. Start the BigClient app in Visual Studio to see that it will work as expected:

To see the full sources and to try it out by yourself, please visit the GitHub repository: https://github.com/JuergenGutsch/di-core-multi-demo

What do you think? Do you have questions or some ideas to add? Feel free to drop a comment :)

ActiveRoute TagHelper

02.03.2017 17:00:00 | Jürgen Gutsch

I recently read the pretty cool blog post by Ben Cull about the IsActiveRoute TagHelper: http://benjii.me/2017/01/is-active-route-tag-helper-asp-net-mvc-core/. This TagHelper adds a css class to an element, if the specified route or route parts are in the current active route. This is pretty useful, if you want to highlight an active item in a menu.

Inspired by this idea, I created a different TagHelper, which shows or hide contents, if the specified route or route parts are in the current route. This could be useful, e.g. if you don't want to have a link in an active menu item.

From the perspective of an semantic web, it doesn't make sense to link to the current page. That means, the menu item that points to the current page should not be a link.

The usage of this TagHelper will look like this:

<ul class="nav navbar-nav">
  <li>
    <a asp-active-route asp-action="Index" asp-controller="Home" asp-hide-if-active="true">
      <span>Home</span>
    </a>
    <span asp-active-route asp-action="Index" asp-controller="Home">Home</span>
  </li>
  <li>
    <a asp-active-route asp-action="About" asp-controller="Home" asp-hide-if-active="true">
      <span>About</span>
    </a>
    <span asp-active-route asp-action="About" asp-controller="Home">About</span>
  </li>
  <li>
    <a asp-active-route asp-action="Contact" asp-controller="Home" asp-hide-if-active="true">
      <span>Contact</span>
    </a>
    <span asp-active-route asp-action="Contact" asp-controller="Home">Contact</span>
  </li>
</ul>

As you may see on the a-Tag, multiple TagHelper can work on a single Tag. In this case the built in AnchorTagHelper and the ActiveRouteTagHelper are manipulating the Tag. The a-Tag will be hidden if the specified route is active and the span-Tag is shown in that case.

If you now navigate to the About page, the a-Tag is removed from the specific menu item and the span-Tag is shown. The HTML result of the menu now looks pretty clean:

<ul class="nav navbar-nav">
  <li>
    <a href="/">
      <span>Home</span>
    </a>
  </li>
  <li>
    <span>About</span>
  </li>
  <li>
    <a href="/Home/About">
      <span>Contact</span>
    </a>
  </li>
</ul>

Using this approach for the menu, we don't need Ben Culls TagHelper here to add a special CSS class. The style for the active item can be set via the selection of that list item with just the span in it:

.nav.navbar-nav li > a { ... }
.nav.navbar-nav li > a > span { ... }
.nav.navbar-nav li > span { ... } /* this is the active item*/

This CSS is based on the default Bootstrap based template in a new ASP.NET Core project. If you use another template, just replace the CSS class which identifies the menu with your specific identifier.

That means, to get that active menu item looking nice, you may just add a CSS like this:

.navbar-nav li > span {
    padding: 15px;
    display: block;
    color: white;
}

This results in the following view:

To get this working, we need to implement the TagHelper. I just created a new class in the project and called it ActiveRouteTagHelper and added the needed properties:

[HtmlTargetElement(Attributes = "asp-active-route")]
public class ActiveRouteTagHelper : TagHelper
{
  [HtmlAttributeName("asp-controller")]
  public string Controller { get; set; }

  [HtmlAttributeName("asp-action")]
  public string Action { get; set; }

  [HtmlAttributeName("asp-hide-if-active")]
  public bool HideIfActive { get; set; }
  
  
}

That class inherits the TagHelper base class. To use it on any HTML tag, I defined a attribute name which is needed to on the HTML we want to manipulate. I used the name "asp-active-route". Also the attributes getting a specific name. I could use the default name, without the leading "asp" prefix, but I thouhgt it would make sense to share the Controller and Action properties with the built-in AnchorTagHelper. And to be consistent, I use the prefix in all cases.

Now we need to override the Process method to actually manipulate the specific HTML tag:

public override void Process(TagHelperContext context, TagHelperOutput output)
{
  if (!CanShow())
  {
    output.SuppressOutput();
  }

  var attribute = output.Attributes.First(x => x.Name == "asp-active-route");
  output.Attributes.Remove(attribute);
}

If I cannot show the Tag because of the conditions in the CahShow() method, I completely suppress the output. Nothing is generated in that case. Not the contents and not the HTML tag itself.

At the end of the method, I remove the identifying attribute, which is used to activate this TagHelper, because this attribute will be kept usually.

To get the RouteData of the current route, we cant use the TagHelperContext or the TagHelperOutput. We need to add the inject the ViewContext:

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

Now we are able to access the route data and get the needed information about the current route:

private bool CanShow()
{
  var currentController = ViewContext.RouteData.Values["Controller"].ToString();
  var currentAction = ViewContext.RouteData.Values["Action"].ToString();

  var show = false;
  if (!String.IsNullOrWhiteSpace(Controller) &&
      Controller.Equals(currentController, StringComparison.CurrentCultureIgnoreCase))
  {
    show = true;
  }
  if (show &&
      !String.IsNullOrWhiteSpace(Action) &&
      Action.Equals(currentAction, StringComparison.CurrentCultureIgnoreCase))
  {
    show = true;
  }
  else
  {
    show = false;
  }

  if (HideIfActive)
  {
    show = !show;
  }

  return show;
}

One last step you need to do, is to register your own TagHelpers. In Visual Studio open the _ViewImports.cshtml and add the following line of code:

@addTagHelper *, CoreWebApplication

Where CoreWebApplication is the assembly name of your project. * means use all TagHelpers in that library

Conclusion

I hope this makes sense to you and helps you a little more to get into the TagHelpers.

I always have fun, creating a new TagHelper. With less code, I'm able to extend the View engine the way I need.

I always focus on semantic HTML, if possible. Because it makes the Web a little more accessible to other devices and engines than we usually use. This could be screen readers for blind people, as well as search engines. Maybe I can do some more posts about accessibility in ASP.NET Core applications.

ActiveRoute TagHelper

02.03.2017 17:00:00 | Jürgen Gutsch

I recently read the pretty cool blog post by Ben Cull about the IsActiveRoute TagHelper: http://benjii.me/2017/01/is-active-route-tag-helper-asp-net-mvc-core/. This TagHelper adds a css class to an element, if the specified route or route parts are in the current active route. This is pretty useful, if you want to highlight an active item in a menu.

Inspired by this idea, I created a different TagHelper, which shows or hide contents, if the specified route or route parts are in the current route. This could be useful, e.g. if you don't want to have a link in an active menu item.

From the perspective of an semantic web, it doesn't make sense to link to the current page. That means, the menu item that points to the current page should not be a link.

The usage of this TagHelper will look like this:

<ul class="nav navbar-nav">
  <li>
    <a asp-active-route asp-action="Index" asp-controller="Home" asp-hide-if-active="true">
      <span>Home</span>
    </a>
    <span asp-active-route asp-action="Index" asp-controller="Home">Home</span>
  </li>
  <li>
    <a asp-active-route asp-action="About" asp-controller="Home" asp-hide-if-active="true">
      <span>About</span>
    </a>
    <span asp-active-route asp-action="About" asp-controller="Home">About</span>
  </li>
  <li>
    <a asp-active-route asp-action="Contact" asp-controller="Home" asp-hide-if-active="true">
      <span>Contact</span>
    </a>
    <span asp-active-route asp-action="Contact" asp-controller="Home">Contact</span>
  </li>
</ul>

As you may see on the a-Tag, multiple TagHelper can work on a single Tag. In this case the built in AnchorTagHelper and the ActiveRouteTagHelper are manipulating the Tag. The a-Tag will be hidden if the specified route is active and the span-Tag is shown in that case.

If you now navigate to the About page, the a-Tag is removed from the specific menu item and the span-Tag is shown. The HTML result of the menu now looks pretty clean:

<ul class="nav navbar-nav">
  <li>
    <a href="/">
      <span>Home</span>
    </a>
  </li>
  <li>
    <span>About</span>
  </li>
  <li>
    <a href="/Home/About">
      <span>Contact</span>
    </a>
  </li>
</ul>

Using this approach for the menu, we don't need Ben Culls TagHelper here to add a special CSS class. The style for the active item can be set via the selection of that list item with just the span in it:

.nav.navbar-nav li > a { ... }
.nav.navbar-nav li > a > span { ... }
.nav.navbar-nav li > span { ... } /* this is the active item*/

This CSS is based on the default Bootstrap based template in a new ASP.NET Core project. If you use another template, just replace the CSS class which identifies the menu with your specific identifier.

That means, to get that active menu item looking nice, you may just add a CSS like this:

.navbar-nav li > span {
    padding: 15px;
    display: block;
    color: white;
}

This results in the following view:

To get this working, we need to implement the TagHelper. I just created a new class in the project and called it ActiveRouteTagHelper and added the needed properties:

[HtmlTargetElement(Attributes = "asp-active-route")]
public class ActiveRouteTagHelper : TagHelper
{
  [HtmlAttributeName("asp-controller")]
  public string Controller { get; set; }

  [HtmlAttributeName("asp-action")]
  public string Action { get; set; }

  [HtmlAttributeName("asp-hide-if-active")]
  public bool HideIfActive { get; set; }
  
  
}

That class inherits the TagHelper base class. To use it on any HTML tag, I defined a attribute name which is needed to on the HTML we want to manipulate. I used the name "asp-active-route". Also the attributes getting a specific name. I could use the default name, without the leading "asp" prefix, but I thouhgt it would make sense to share the Controller and Action properties with the built-in AnchorTagHelper. And to be consistent, I use the prefix in all cases.

Now we need to override the Process method to actually manipulate the specific HTML tag:

public override void Process(TagHelperContext context, TagHelperOutput output)
{
  if (!CanShow())
  {
    output.SuppressOutput();
  }

  var attribute = output.Attributes.First(x => x.Name == "asp-active-route");
  output.Attributes.Remove(attribute);
}

If I cannot show the Tag because of the conditions in the CahShow() method, I completely suppress the output. Nothing is generated in that case. Not the contents and not the HTML tag itself.

At the end of the method, I remove the identifying attribute, which is used to activate this TagHelper, because this attribute will be kept usually.

To get the RouteData of the current route, we cant use the TagHelperContext or the TagHelperOutput. We need to add the inject the ViewContext:

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

Now we are able to access the route data and get the needed information about the current route:

private bool CanShow()
{
  var currentController = ViewContext.RouteData.Values["Controller"].ToString();
  var currentAction = ViewContext.RouteData.Values["Action"].ToString();

  var show = false;
  if (!String.IsNullOrWhiteSpace(Controller) &&
      Controller.Equals(currentController, StringComparison.CurrentCultureIgnoreCase))
  {
    show = true;
  }
  if (show &&
      !String.IsNullOrWhiteSpace(Action) &&
      Action.Equals(currentAction, StringComparison.CurrentCultureIgnoreCase))
  {
    show = true;
  }
  else
  {
    show = false;
  }

  if (HideIfActive)
  {
    show = !show;
  }

  return show;
}

One last step you need to do, is to register your own TagHelpers. In Visual Studio open the _ViewImports.cshtml and add the following line of code:

@addTagHelper *, CoreWebApplication

Where CoreWebApplication is the assembly name of your project. * means use all TagHelpers in that library

Conclusion

I hope this makes sense to you and helps you a little more to get into the TagHelpers.

I always have fun, creating a new TagHelper. With less code, I'm able to extend the View engine the way I need.

I always focus on semantic HTML, if possible. Because it makes the Web a little more accessible to other devices and engines than we usually use. This could be screen readers for blind people, as well as search engines. Maybe I can do some more posts about accessibility in ASP.NET Core applications.

Regeln | Impressum