2017-06-05 21 views
0

我想使用套接字發送/接收數據在ASP.NET核心。我跟着我找到的幾個教程,但我似乎無法得到任何工作。無論我在我的網站上嘗試什麼,套接字連接器都處於「連接/打開」狀態。不能讓套接字在ASP.NET核心工作

這是我試過的教程:

我startup.cs文件中使用的一個看起來像這樣:

using System; 
using System.Text; 
using arnvanhoutte.Data; 
using arnvanhoutte.Models; 
using arnvanhoutte.Services; 
using Microsoft.AspNetCore.Builder; 
using Microsoft.AspNetCore.Hosting; 
using Microsoft.AspNetCore.Http; 
using Microsoft.AspNetCore.Identity; 
using Microsoft.AspNetCore.Identity.EntityFrameworkCore; 
using Microsoft.EntityFrameworkCore; 
using Microsoft.Extensions.Configuration; 
using Microsoft.Extensions.DependencyInjection; 
using Microsoft.Extensions.Logging; 
using Microsoft.Extensions.Options; 
using Microsoft.IdentityModel.Tokens; 

namespace arnvanhoutte 
{ 
    public class Startup 
    { 
     public Startup(IHostingEnvironment env) 
     { 
      Console.WriteLine(env.EnvironmentName); 
      var builder = new ConfigurationBuilder() 
       .SetBasePath(env.ContentRootPath) 
       .AddJsonFile("appsettings.json", true, true) 
       .AddJsonFile($"appsettings.{env.EnvironmentName}.json", true); 

      Console.WriteLine(Configuration.GetConnectionString("DefaultConnection")); 
      if (env.IsDevelopment()) 
      { 
       builder.AddUserSecrets("aspnet-arnvanhoutte-8942961e-3f9b-48f6-a54d-907858e0ad3a"); 
      } 

      builder.AddEnvironmentVariables(); 
      Configuration = builder.Build(); 
     } 

     private IConfigurationRoot Configuration { get; } 

     // This method gets called by the runtime. Use this method to add services to the container. 
     public void ConfigureServices(IServiceCollection services) 
     { 
      services.AddSingleton(_ => Configuration); 

      // Add framework services. 
      services.AddDbContext<ApplicationDbContext>(options => 
       options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); 

      services.AddIdentity<ApplicationUser, IdentityRole>() 
       .AddEntityFrameworkStores<ApplicationDbContext>() 
       .AddDefaultTokenProviders(); 

      services.AddMvc(); 

      services.Configure<IdentityOptions>(opt => 
      { 
       opt.Cookies.ApplicationCookie.LoginPath = new PathString("/Admin/User/Login"); 
      }); 

      // Add application services. 
      services.AddTransient<IEmailSender, AuthMessageSender>(); 
      services.AddTransient<ISmsSender, AuthMessageSender>(); 
      services.AddTransient<Seed>(); 
     } 

     // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 
     public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IServiceProvider serviceProvider, Seed seeder) 
     { 

      loggerFactory.AddConsole(Configuration.GetSection("Logging")); 
      loggerFactory.AddDebug(); 
      loggerFactory.AddAzureWebAppDiagnostics(); 

      seeder.SeedRoles().ConfigureAwait(false); 
      seeder.SeedAdminUser().ConfigureAwait(false); 
      seeder.SeedTestUser().ConfigureAwait(false); 



      app.UseDefaultFiles(); 
      app.UseStaticFiles(); 
      app.Map("/ws", SocketHandler.Map); 

      if (env.IsDevelopment()) 
      { 
       app.UseDeveloperExceptionPage(); 
       app.UseDatabaseErrorPage(); 
      } 
      else 
      { 
       app.UseExceptionHandler("/Home/Error"); 
      } 

      if (env.IsDevelopment()) 
      { 
       app.Use(async (context, next) => 
       { 
        var request = context.Request; 
        if (request.IsHttps) 
        { 
         await next(); 
        } 
        else 
        { 
         var devPort = Configuration.GetValue<int>("iisSettings:iisExpress:sslPort"); 

         var host = new HostString(request.Host.Host, devPort); 

         string newUrl = $"https://{host}{request.PathBase}{request.Path}{request.QueryString}"; 
         context.Response.Redirect(newUrl, true); 
        } 
       }); 
      } 

      app.UseIdentity(); 

      // secretKey contains a secret passphrase only your server knows 
      var secretKey = Configuration.GetSection("AppSettings")["SecretKey"]; 
      var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(secretKey)); 

      var options = new TokenProviderOptions 
      { 
       Path = "/token", 
       Audience = "User", 
       Issuer = "arnvanhoutte", 
       SigningCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256), 
       IdentityResolver = (username, password) => 
       { 
        using (
         var serviceScope = 
          app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope()) 
        { 
         var userManager = serviceScope.ServiceProvider.GetService<UserManager<ApplicationUser>>(); 

         var user = userManager.FindByNameAsync(username).Result; 

         if (user != null && userManager.CheckPasswordAsync(user, password).Result) 
         { 
          return user; 
         } 

         // Credentials are invalid, or account doesn't exist 
         return null; 
        } 
       } 
      }; 

      var tokenValidationParameters = new TokenValidationParameters 
      { 
       // The signing key must match! 
       ValidateIssuerSigningKey = true, 
       IssuerSigningKey = signingKey, 

       // Validate the JWT Issuer (iss) claim 
       ValidateIssuer = true, 
       ValidIssuer = "arnvanhoutte", 

       // Validate the JWT Audience (aud) claim 
       ValidateAudience = true, 
       ValidAudience = "User", 

       // Validate the token expiry 
       ValidateLifetime = true, 

       // If you want to allow a certain amount of clock drift, set that here: 
       ClockSkew = TimeSpan.Zero 
      }; 

      app.UseJwtBearerAuthentication(new JwtBearerOptions 
      { 
       AutomaticAuthenticate = true, 
       AutomaticChallenge = true, 
       TokenValidationParameters = tokenValidationParameters 
      }); 

      app.UseCookieAuthentication(new CookieAuthenticationOptions 
      { 
       AutomaticAuthenticate = true, 
       AutomaticChallenge = true, 
       AuthenticationScheme = "Cookie", 
       LoginPath = new PathString("/login"), 
       AccessDeniedPath = new PathString("/login"), 
       ReturnUrlParameter = "redirect", 
       CookieName = "access_token", 
       TicketDataFormat = new CustomJwtDataFormat(
        SecurityAlgorithms.HmacSha256, 
        tokenValidationParameters) 
      }); 

      app.UseMiddleware<TokenProviderMiddleware>(Options.Create(options)); 

      app.UseMvc(routes => 
      { 
       routes.MapRoute("myProjects", 
        "{area:exists}/{controller=Home}/{action=Index}/{id?}"); 

       routes.MapRoute(
        "default", 
        "{controller=Home}/{action=Index}/{id?}"); 
      }); 
     } 
    } 
} 

這是sockethandler.cs文件:

using System; 
using System.Net.WebSockets; 
using System.Threading; 
using System.Threading.Tasks; 
using Microsoft.AspNetCore.Builder; 
using Microsoft.AspNetCore.Http; 

namespace arnvanhoutte.Services 
{ 
    public class SocketHandler 
    { 
     public const int BufferSize = 4096; 

     private readonly WebSocket _socket; 

     private SocketHandler(WebSocket socket) 
     { 
      _socket = socket; 
     } 

     private async Task EchoLoop() 
     { 
      var buffer = new byte[BufferSize]; 
      var seg = new ArraySegment<byte>(buffer); 

      while (_socket.State == WebSocketState.Open) 
      { 
       var incoming = await _socket.ReceiveAsync(seg, CancellationToken.None); 
       var outgoing = new ArraySegment<byte>(buffer, 0, incoming.Count); 
       await _socket.SendAsync(outgoing, WebSocketMessageType.Text, true, CancellationToken.None); 
      } 
     } 

     private static async Task Acceptor(HttpContext hc, Func<Task> n) 
     { 
      if (!hc.WebSockets.IsWebSocketRequest) 
       return; 

      var socket = await hc.WebSockets.AcceptWebSocketAsync(); 
      var h = new SocketHandler(socket); 
      await h.EchoLoop(); 
     } 
     public static void Map(IApplicationBuilder app) 
     { 
      app.UseWebSockets(); 
      app.Use(Acceptor); 
     } 
    } 
} 

這是HTML文件,我服:

@{ 
    Layout = null; 
} 
<div id="output"></div> 

<script language="javascript" type="text/javascript"> 

    var socket; 
    var uri = "ws://" + window.location.host + "/ws"; 
    var output; 
    var text = "test echo"; 

    function write(s) { 
     var p = document.createElement("p"); 
     p.innerHTML = s; 
     output.appendChild(p); 
    } 

    function doConnect() { 
     socket = new WebSocket(uri); 
     socket.onopen = function (e) { write("opened " + uri); doSend(); }; 
     socket.onclose = function (e) { write("closed"); }; 
     socket.onmessage = function (e) { write("Received: " + e.data); socket.close(); }; 
     socket.onerror = function (e) { write("Error: " + e.data); }; 
    } 

    function doSend() { 
     write("Sending: " + text); 
     socket.send(text); 
    } 

    function onInit() { 
     output = document.getElementById("output"); 
     doConnect(); 
    } 

    window.onload = onInit; 

</script> 

當我運行這一點,並定位到該文件,沒有最初顯示。經過一段時間後,我在控制檯中得到這個錯誤:sockettest:17 WebSocket connection to 'ws://localhost:44399/ws' failed: Error during WebSocket handshake: net::ERR_CONNECTION_RESET

+0

您的教程鏈接不正確。 – mjwills

+0

@mjwills哎呀,修正了它 – user2657943

回答

2

我找到了解決辦法!問題在於谷歌瀏覽器阻止了我的websockets,我認爲是因爲不安全的證書。解決的辦法是用這裏找到的腳本生成一個合法證書:https://github.com/webpack/webpack-dev-server/issues/854

然後我還必須將uri更改爲wss://而不是ws://。然後一切正常

+1

好的,你有點不對,問題是Chrome不允許混合HTTP和HTTPS,所以如果你的頁面是HTTPS,你必須使用SSL websockets('wss://'而不是'ws://') – Gusman

+0

是的,但是它在接受我的證書後纔給了我警告。在它什麼都沒說並且停留在開放狀態之前 – user2657943

1

你是不是調用SocketHandler類的Map功能在你的StartupConfigure功能。

Configure功能補充一點:

SocketHandler.Map(app); 
+0

我首先在'Configure'函數的頂部添加了這個,然後甚至沒有通過html文件。然而,最後它確實將html文件發送到瀏覽器,但是套接字仍然不起作用。 – user2657943

+0

您是否檢查過,當您向服務器發出websocket請求時,是否正在調用acceptor函數? – Gusman

+0

我添加了一個斷點,但它永遠不會被稱爲 – user2657943