请选择 进入手机版 | 继续访问电脑版

技术控

    今日:13| 主题:54628
收藏本版 (1)
最新软件应用技术尽在掌握

[其他] Real-time applications using ASP.NET Core, SignalR & Angular

[复制链接]
Lonelypartn 发表于 2016年10月10日 19:51
223 3

立即注册CoLaBug.com会员,免费获得投稿人的专业资料,享用更多功能,玩转个人品牌!

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
Real-time web applications are apps that push user experience to the limits while trying to immediately reflect data changes to a great number of connected clients. You make use of such applications on a daily basis, Facebook and Twitter are some of them. There are several ways to design and implement Real-time web applications and of course Microsoft made sure to provide you with a remarkable library named SignalR . The idea behind SignalR is let the server push changes automatically to connected clients instead of having each client polling the server on time intervals. And what does connected clients means anyway? The answer is hidden behind the concept of the HTTP persistent connections which are connections that may remain opened for a long time, in contrast with the tradional HTTP Connections that can be disconnected. The persistent connection remains opened due to certain type of packet exchanging between a client and the server. When a client calls a SignalR method on the server, the server is able to uniquely identify the connection ID of the caller.
  What this post is all about

   SignalR has been out for a long time but ASP.NET Core and Angular 2 aren’t. On this post we ‘ll see what takes to bind all those frameworks and libraries together and build a Real time application. This is not an Angular tutorial nor a SignalR one. Because of the fact that the final project associated to this post contains code that we have already seen on previous posts, I will only explain the parts that you actually need to know in order to build a real time application. And this is why I will strongly recomend you to download the Live-Game-Feed app and study the code along with me without typing it. Here’s what we ‘ll see in more detail..
  
       
  • Fire up an empty ASP.NET Core web application using yeoman   
  • Configure and install MVC and SignalR Server dependencies   
  • Install SignalR Client-Typescript dependencies   
  • Create a SignalR hub   
  • Integrate  MVC Controllers (API)  with SignalR   
  • Create the Angular-SignalR service to communicate with SignalR hubs   
  • Add Reccurent Tasks on a ASP.NET Core application   
  • Have fun with the final App!  
  About the LiveGameFeed app

   The app simulates a web application that users may visit and watch matches live. I am sure you are aware of plenty of such websites, most of them are related to betting. The idea is that there will be two matches running, and every time score is updated all connected clients will receive the update. On the other hand, if a user also wants to getting live feed for a specific match then he/she has to be subscibed to the match. More over, if subscribed, the user will be able to post messages related to that match while those messages will be pushed and read only by users also subscribed to the that match. Why don’t we take a look at the LiveGameFeed app (zoom out a little bit if needed so that you can see both clients) ..
   

Real-time applications using ASP.NET Core, SignalR & Angular

Real-time applications using ASP.NET Core, SignalR & Angular-1-技术控-experience,Facebook,Microsoft,connected,contrast

  Are you ready? Let’s start!
  Fire up an empty ASP.NET Core web application using yeoman

   I assume you have already installed .NET Core on your platform and you have opened the Live-Game-Feed app on your favorite text editor. You can start a .NET Core application either using the dotnet-new cli command or using the open-source yeoman tool. I picked the latter choise cause there are some great options to fire up a ASP.NET Core application. In order to use yeoman you need to run the following commands.
  1. npm install -g yo bower
复制代码
  1. npm install -g generator-aspnet
复制代码
Next, open a console and navigate where you want to fire up the project and run the following command:
  1. yo aspnet
复制代码
The tool will give you some options to start with.
   

Real-time applications using ASP.NET Core, SignalR & Angular

Real-time applications using ASP.NET Core, SignalR & Angular-2-技术控-experience,Facebook,Microsoft,connected,contrast

   Select Empty Web Application and give a name for your app.
   

Real-time applications using ASP.NET Core, SignalR & Angular

Real-time applications using ASP.NET Core, SignalR & Angular-3-技术控-experience,Facebook,Microsoft,connected,contrast

   Open the created folder in your editor (mine is Visual Studio Code ) and check the files created. Those are the minimum files required for an empty Web Application. Navigate inside the app’s root folder and restore .NET packages by running the following command.
  1. dotnet restore
复制代码
As you can see, Visual Studio Code has also an integrated terminal which certainly makes your life easier.
   

Real-time applications using ASP.NET Core, SignalR & Angular

Real-time applications using ASP.NET Core, SignalR & Angular-4-技术控-experience,Facebook,Microsoft,connected,contrast

  Then make sure that all have been set properly by running the app..
  1. dotnet run
复制代码
  Of course you will only get the famous Hello world! response but it’s more than enough at the moment.
  Configure and install MVC and SignalR Server dependencies

   The next step in to install ASP.NET Core MVC and SignalR packages and add them into the pipeline as well. Your project.json file should look like this:
  1. {
  2.   "dependencies": {
  3.     "AutoMapper.Data": "1.0.0-beta1",
  4.     "Microsoft.NETCore.App": {
  5.       "version": "1.0.0-*",
  6.       "type": "platform"
  7.     },
  8.     "Microsoft.AspNet.WebApi.Client": "5.1.1",
  9.     "Microsoft.AspNetCore.Mvc": "1.0.1",
  10.     "Microsoft.AspNetCore.Routing": "1.0.1",
  11.     "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
  12.     "Microsoft.AspNetCore.Server.Kestrel": "1.0.1",
  13.     "Microsoft.AspNetCore.SignalR.Server": "0.2.0-*",
  14.     "Microsoft.AspNetCore.StaticFiles": "1.1.0-*",
  15.     "Microsoft.AspNetCore.WebSockets": "0.2.0-*",
  16.     "Microsoft.EntityFrameworkCore": "1.0.1",
  17.     "Microsoft.EntityFrameworkCore.InMemory": "1.0.0",
  18.     "Microsoft.EntityFrameworkCore.Relational": "1.0.1",
  19.     "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0",
  20.     "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0",
  21.     "Microsoft.Extensions.Configuration.Json": "1.0.0",
  22.     "Microsoft.Extensions.Configuration.CommandLine": "1.0.0",
  23.     "Microsoft.Extensions.Logging": "1.0.0",
  24.     "Microsoft.Extensions.Logging.Console": "1.0.0",
  25.     "Microsoft.Extensions.Logging.Debug": "1.0.0",
  26.     "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0",
  27.     "RecurrentTasks": "3.0.0-beta1"
  28.   },

  29.   "tools": {
  30.     "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final"
  31.   },

  32.   "frameworks": {
  33.     "netcoreapp1.0": {
  34.       "imports": [
  35.         "dotnet5.6",
  36.         "portable-net45+win8"
  37.       ]
  38.     }
  39.   },

  40.   "buildOptions": {
  41.     "emitEntryPoint": true,
  42.     "preserveCompilationContext": true,
  43.     "debugType": "portable"
  44.   },

  45.   "runtimeOptions": {
  46.     "configProperties": {
  47.       "System.GC.Server": true
  48.     }
  49.   },

  50.   "publishOptions": {
  51.     "include": [
  52.       "wwwroot",
  53.       "Views",
  54.       "Areas/**/Views",
  55.       "appsettings.json",
  56.       "web.config"
  57.     ]
  58.   },

  59.   "scripts": {
  60.     "postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
  61.   },

  62.   "tooling": {
  63.     "defaultNamespace": "LiveGameFeed"
  64.   }
  65. }
复制代码
Following are the most interesting packages to notice:
  1. "Microsoft.AspNetCore.Mvc": "1.0.1"
  2. "Microsoft.AspNetCore.SignalR.Server": "0.2.0-*"
  3. "Microsoft.AspNetCore.WebSockets": "0.2.0-*"
复制代码
If you try to restore the packages you will get the following error..
  1. log  : Restoring packages for c:\Users\chsakell\Desktop\LiveGameFeed\project.json...                                                                                                            
  2. error: Unable to resolve 'Microsoft.AspNetCore.SignalR.Server (>= 0.2.0)' for '.NETCoreApp,Version=v1.0'.                                                                                                   
  3. error: Unable to resolve 'Microsoft.AspNetCore.StaticFiles (>= 1.1.0)' for '.NETCoreApp,Version=v1.0'.                                                                                                      
  4. error: Unable to resolve 'Microsoft.AspNetCore.WebSockets (>= 0.2.0)' for '.NETCoreApp,Version=v1.0'.                                                                                                        
  5. log  : Restoring packages for tool 'Microsoft.AspNetCore.Server.IISIntegration.Tools' in c:\Users\chsakell\Desktop\LiveGameFeed\project.json...                                                  
  6. log  : Writing lock file to disk. Path: c:\Users\chsakell\Desktop\LiveGameFeed\project.lock.json                                                                                                
  7. log  : c:\Users\chsakell\Desktop\LiveGameFeed\project.json                                                                                                                                       
  8. log  : Restore failed in 10232ms.                                                                                                                                                                           
  9.                                                                                                                                                                                                             
  10. Errors in c:\Users\chsakell\Desktop\LiveGameFeed\project.json                                                                                                                                    
  11. Unable to resolve 'Microsoft.AspNetCore.SignalR.Server (>= 0.2.0)' for '.NETCoreApp,Version=v1.0'.                                                                                                      
  12. Unable to resolve 'Microsoft.AspNetCore.StaticFiles (>= 1.1.0)' for '.NETCoreApp,Version=v1.0'.                                                                                                         
  13. Unable to resolve 'Microsoft.AspNetCore.WebSockets (>= 0.2.0)' for '.NETCoreApp,Version=v1.0'.
复制代码
  This error occurred cause you miss NuGet package configuration which is needed in order to install the SignalR and WebSockets packages. Add a NuGet.config file at the root of your app and set it as follow:
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <configuration>
  3.   <packageSources>
  4.     <add key="AspNetCore" value="https://dotnet.myget.org/F/aspnetcore-ci-dev/api/v3/index.json" />
  5.     <add key="NuGet" value="https://api.nuget.org/v3/index.json" />
  6.   </packageSources>
  7. </configuration>
复制代码
  Now the dotnet restore command will not fail. You add MVC and SignalR into the pipeline in the same way you add any other middleware. In the Startup.cs file you will find the following commands into the ConfigureServices method..
  1. // Add framework services.
  2. services
  3.     .AddMvc()
  4.     .AddJsonOptions(options => options.SerializerSettings.ContractResolver =
  5.         new DefaultContractResolver());

  6. services.AddSignalR(options => options.Hubs.EnableDetailedErrors = true);
复制代码
  .. and in the Configure method..
  1. npm install -g generator-aspnet0
复制代码
  You will find that in the finished Startup.cs file I have also set dependency injection for the data repositories, Entity Framework InMemoryDatabase provider and some recurrent tasks to run using the RecurrentTasks package. We ‘ll talk about the latter little bit before firing the final app.
  Install SignalR Client-Typescript dependencies

   The client side will be written in TypeScript entirely and this is something new since in most of the SignalR tutorials the client side were written in pure javascript and jQuery. In case you are familiar with Angular 2 then you already know how to intall npm packages. You need to create a package.json file under the root and also make sure you add the signalr as a dependency.
  1. npm install -g generator-aspnet1
复制代码
  Next you need to add the required typings by adding a typings.json file.
  1. npm install -g generator-aspnet2
复制代码
  The tsconfig.json TypeScript configuration file.
  1. npm install -g generator-aspnet2
复制代码
  And finally the bower.json .
  1. npm install -g generator-aspnet4
复制代码
  At this point you can run the npm install command to install all the NPM packages and typings as well.
  Create a SignalR hub

   A Hub is nothing but a C# class derived from the Microsoft.AspNetCore.SignalR.Hub . The idea is that clients may connect to a certain Hub and hence it’s logic that this class would implement methods such as OnConnected or OnDisconnected . Let’s view the abstract class in more detail.
  1. npm install -g generator-aspnet5
复制代码
  A Hub can implement methods that the client may call and vice versa, the SignalR client may implement methods that the Hub may invoke. That’s the power of SignalR. Our app has a simple Hub named Broadcaster under the Hubs folder.
  1. npm install -g generator-aspnet6
复制代码
Let’s discuss the above class in detail.
  
       
  • Broadcaster implements the OnConnected method by calling a client-side SignalR method named setConnectionId . The OnConnected event fires when the client calls the start method on the accossiated hub connection. It’s going to look like this:
    1. npm install -g generator-aspnet7
    复制代码
      
  • The Clients property holds references to all connected clients.
    1. npm install -g generator-aspnet8
    复制代码
             Before invoking a client method, you can target specific clients. On the above example we targeted only the caller using the Client(Context.ConnectionId) . There are other options though as you can see.
         

    Real-time applications using ASP.NET Core, SignalR & Angular

    Real-time applications using ASP.NET Core, SignalR & Angular-5-技术控-experience,Facebook,Microsoft,connected,contrast
       
  • SignalR lets you group clients using the Group property.
    1. npm install -g generator-aspnet9
    复制代码
    Broadcaster Hub, has two server methods that clients may call in order to subscribe/unsubscribe to/from certain chat groups. In SignalR, all you have to do is add/remove the respective client connection id to/from the respective group. Here we set that the group name is equal to the matchId that the client wants to listen messages for. Later on, when the server needs to send a message to a certain group, all it takes to do is the following..
    1. yo aspnet0
    复制代码
    What the previous line of code does, is invoke the addChatMessage(message) client-side method only to those clients that have been subscribed to the group named message.MatchId.ToString() .
       
  • Subscribe and Unsubscribe are the only methods that our hub implements and can be called from the client. The client though will implement much more methods and most of them will be invoked through the MVC Controllers. As you noticed, in order to call a client-side method you need reference to the IHubCallerConnectionContext Clients property but for this, we need to integrate MVC with SignalR.  
   We have also used an interface so we have typed support for calling client side methods. You can omit this behavior and simply derive the class from Hub .
  Integrate MVC Controllers (API) with SignalR

   This is the most important part of the post, making Hubs functionality available to MVC Controllers. The reason why this is that much important is based on the web application architectural patterns where clients usual make HTTP calls to REST APIs , with the only difference this time the API is also responsible to send notifications to a batch of other connected clients as well. For example, in the context of a chat conversation, if a user posts a new message to a MessagesController API Controller and that message needs to be delived to all participants, the API Controller should be able to immediately push and deliver the message to all of them.
   

Real-time applications using ASP.NET Core, SignalR & Angular

Real-time applications using ASP.NET Core, SignalR & Angular-6-技术控-experience,Facebook,Microsoft,connected,contrast

   The image denotes that SignalR server can communicate with SignalR clients either via a direct “channel” between the Hub and the client or through an integrated MVC Controller which does nothing but access and use Hub’s properties. To achieve our goal, we ‘ll make any MVC Controller that we want to use SignalR derived from the following abstract ApiHubController class. You will find that class inside the Controllers folder.
  1. yo aspnet1
复制代码
The most important line of the previous class is the following:
  1. yo aspnet2
复制代码
  Getting the instance of the Microsoft.AspNetCore.SignalR.IHubContext will give us access to both the Clients and the Groups properties. Let us view the interface in detail..
  1. yo aspnet3
复制代码
  The where T : Hub means that you can create as many Hub classes as you want and make them available to any MVC Controller on demand. Now let’s see an example where we actually use this class. LiveGameFeed app has a MatchesController MVC Controller which basically is used for two reasons. First for retrieving available matches that our app serves and second, when score is updated on a match, pushes the change to all connected clients.
  1. yo aspnet4
复制代码
  We get an instance of IHubContext for the Broadcaster Hub..
  1. yo aspnet5
复制代码
  When a match score is updated we want to notifify all connected clients, regardless if they are subscribed or not to the related feed. The client is going to implement an updateMatch function that can be called from the Hub.
  1. yo aspnet6
复制代码
  In a similar way you will find a FeedsController MVC Controller where when a new Feed is added to a match, the API notifies those clients that not only are connected but also subscribed to that match feed. Since we want to target only the clients subscribed to the group named equal to the matchId, we use the Group property as follow.
  1. yo aspnet7
复制代码
Create the Angular-SignalR service to communicate with SignalR hubs

   Well here’s the tricky part. First of all you should know that the server will generate a client hubs proxy for you at the signalr/js location and this why you will find a reference to this file in the Views/Index.cshtml view. This script contains a jQuery.connection object that allows you to reference any hub you have defined on the server side. In many tutorials where the client side is implemented purely in jQuery you would probably find code similar to the following:
  1. yo aspnet8
复制代码
  The code references a hub named Broadcaster and defines a client side method on the broadcaster.client object. Notice the lowercase .broadcaster declaration that connects to a Hub class named Broadcaster . You can customize both the custom Hub name and the path where the server will render the proxy library. We need though to switch to TypeScript so let’s define interfaces for the SignalR related objects. You will find them in the interfaces.ts file.
  1. yo aspnet9
复制代码
  The SignalR interface is defined in the typings/globals/signalr/index.d.ts and we installed it via typings. The FeedProxy will contain references to the client and server hub connection objects respectively. Any client side method that we want to be invoked from the server be implemented on the client object and any server side method implemented on the server (e.g. Subscribe, Unsubscribe) will be called through the server object. The FeedClient is where you define any client side method you are going to implement and the FeedServer contains the server methods you are going to invoke. Again the methods are in lowercase and matches the uppercase relative method on the server. If you don’t use this convetion you will not be able to call the server methods. The feed.service.ts file is an @Injectable angular service where we implement our interfaces.
  Implement client-side methods

   The pattern is simple and we will examine the case of the addChatMessageSubject client side method. First you define an Observable property of type ChatMessage cause when called from the server, it will accept a parameter of type ChatMessage .
  1. dotnet restore0
复制代码
  .. the ChatMessage looks like that and of course there is a relative server ViewModel on the server.
  1. dotnet restore1
复制代码
  Then you define rxjs/Subject property for that method.
  1. dotnet restore2
复制代码
.. and you make sure to make the following assignment on the service’s constructor:
  1. dotnet restore3
复制代码
  The next step is to define a method (or event if you prefer) where you respond to the observable events.
  1. dotnet restore4
复制代码
  There is a last step where you actually bind this method on the client property of the hubs connection but first we need to configure our proxy. This is done on the start method as follow..
  1. dotnet restore5
复制代码
  In case you had more than one hubs, for example a hub class OtherHub you would reference that hub as follow:
  1. dotnet restore6
复制代码
  And of course you would have to declare any methods to be called from that hub, on the otherHub.client object and so on.. We followed the observable pattern which means that any client-component that wants to react when a client method is invoked from the server, needs to be subscribed. The chat.component.ts listens for chat messages:
  1. dotnet restore7
复制代码
  But remember.. in the LiveGameFeed app, this method will be called only on those clients that are subscribed on the relative match. This is defined on the MessagesController MVC Controller, when a chat message is posted.
  1. dotnet restore8
复制代码
  The methods that can be called on the server are way much easier to implement since are just methods defined on the connection.server object.
  1. dotnet restore9
复制代码
Add Reccurent Tasks on a ASP.NET Core application

   You may have noticed that in the project.json there is a RecurrentTasks package reference. I used that package in order to simulate live updates and make easier for you to see SignalR in action. In the Core folder you will find a FeedEngine class that triggers updates on specific time intervals.
  1. dotnet run0
复制代码
  There are two type of updates. A match score update which will be pushed to all connected clients though the MatchesController MVC Controller and feed updates being pushed through th FeedsController . In the Startup class you will also find how we configure this IRunnable task class to be triggered on time intervals.
  1. dotnet run1
复制代码
Have fun with the app!

   I guess you have already downloaded or cloned the repository related to this post as I mentioned on start. In order to fire the app you need to run the following commands (open two terminals and navigate to the project) The first three will download NPM and Bower packages and compile the angular app. Also it will be watching for TypeScript changes during development..
  1. dotnet run2
复制代码
and the .NET Core related that will restore the packages and run the server.
  1. dotnet run3
复制代码
  Open as many browser tabs or windows as you wish and start playing with the app. Every 15 seconds the app will trigger updates and all clients will receive at least the score update. If subscribed, they will receive the feed and any messages related to the match as well. Mind that two tabs on the same window browser are two different clients for SignalR which means have a different Connection Id . The connection id for each client is displayed on the chat component. On new feed received event, the new row to be displayed is highlighted for a while. Here is the angular directive responsible for this functionality.
  1. dotnet run4
复制代码
Conclusion

   SignalR library is awesome but you need to make sure that this is the right choice to make before using it. In case you have multiple clients that is important to push them updates on real time then you are good to go. That’s it, we finally finished! We have seen how to setup an ASP.NET Core project that leverages SignalR library through MVC Controllers. More over we used SignalR typings in order to create and use the SignalR client library using Angular and TypeScript.
   Source Code: You can find the source code for this project here where you will also find instructions on how to run the application.
   In case you find my blog’s content interesting, register your email to receive notifications of new posts and follow chsakell’s Blog on its Facebook or Twitter accounts.



上一篇:A Beginners Guide to JXA, JavaScript Application Scripting
下一篇:微网站:让你的网站在用户的手机里安家
edi3son 发表于 2016年10月10日 20:51
人生最痛苦的事就是方便面涨价了。
回复 支持 反对

使用道具 举报

借幸福给你 发表于 2016年11月8日 06:00
发贴技术哪家强?Lonelypartn
回复 支持 反对

使用道具 举报

飞天是 发表于 2016年11月21日 08:39
非常好,顶一下
回复 支持 反对

使用道具 举报

*滑动验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

我要投稿

推荐阅读


回页顶回复上一篇下一篇回列表
手机版/CoLaBug.com ( 粤ICP备05003221号 | 文网文[2010]257号 )

© 2001-2017 Comsenz Inc. Design: Dean. DiscuzFans.

返回顶部 返回列表