Угловой проект .NET не может отправлять данные, если соединение не находится в подключенном состоянии? - PullRequest
1 голос
/ 20 сентября 2019

Я запускаю угловой проект .NET в VScode для Windows и пытаюсь заставить работать signalR, но, к сожалению, все идет не так, как надо. До того, как у меня было ядро ​​angular и .netпроекты, разделенные (веб-API и угловой проект отдельно) с одним и тем же кодом, этой проблемы не возникало.Это когда я переключился на основной угловой проект .NET, это сейчас происходит.Заранее спасибо.

при попытке отправить сообщение на сервер я получаю следующую ошибку

enter image description here ChatHub.cs

using System;
using System.Threading.Tasks;
using System.Collections.Generic;

using Microsoft.AspNetCore.SignalR;

namespace ProjectConker
{
    public class IMessage
    {
       public string timestamp;
       public string message;
       public string author;
       public string iconLink;
   }
    public class ChatHub : Hub
    {
        public Task SendToAll(string name, IMessage messageData)
        {
            Console.WriteLine(messageData.message);
             return Clients.All.SendAsync("ReceiveMessage", name, messageData);
        }
    } 
}

угловой клиентский компонент


import { Component, OnInit } from '@angular/core';
import { ITag } from '../Tag/tag';
import { TagComponent } from '../Tag/tag.component';
import { Router, ActivatedRoute, ParamMap, Params } from '@angular/router';
import { switchMap } from 'rxjs/operators';
import { Observable } from 'rxjs';
import { IMessage } from './Message';
import { HubConnection, HubConnectionBuilder, HttpTransportType } from '@aspnet/signalr';
import { HttpClient } from '@angular/common/http';



@Component({
  selector: 'chat',
  templateUrl: "./chatComponent.component.html",
  styleUrls: ['./chatComponent.component.css']
  // providers: [ ChatService ]
})

export class ChatComponent implements OnInit {

  hubConnection: HubConnection;

  messageData: IMessage;
  message: string;

  //profile info
  author: string;
  iconLink: string;

  messages: IMessage[] = [];

  constructor(
    private route: ActivatedRoute,
    private router: Router,
    private http: HttpClient
  ) { }

  ngOnInit() {

    this.getRandomUser();

    this.hubConnection = new HubConnectionBuilder().withUrl("http://localhost:5000/api/chat", {
      skipNegotiation: true,
      transport: HttpTransportType.WebSockets
    }).build();

    this.hubConnection
      .start()
      .then(() => console.log('Connection started!'))
      .catch(err => console.log('Error while establishing connection :('));

    this.hubConnection.on('ReceiveMessage', (author: string, receivedMessage: IMessage) => {

      this.messages.push(receivedMessage);
    });

  }

  private getRandomUser() {
    this.http.get("https://randomuser.me/api/")
      .subscribe(
        (data: any) => {
          console.log(data);

          this.iconLink = data.results[0].picture.medium;
          this.author = data.results[0].name.first;

          console.log(this.iconLink);
        }
      );

  }

  public sendMessage(): void {

    var today = new Date();

    this.messageData = {
      author: this.author,
      message: this.message,
      timestamp: ("0" + today.getHours()).toString().slice(-2) + ":" + ("0" + today.getMinutes()).toString().slice(-2),
      iconLink: this.iconLink
    };
    this.hubConnection
      .invoke('SendToAll', this.author, this.messageData)
      .catch(err => console.error(err));

    this.message = '';
  }


}

угловой клиентский просмотр

 <div class="outer-chat-container">
    <div class="chat-container">

        <ng-container *ngIf="messages.length > 0">
            <div class="message-box"  *ngFor="let message of messages">
              <img class="avatar" [src]='message.iconLink'>


              <div class="content">
                <div class="headline">
                    <p class="author">{{ message.author }}</p>
                    <div class="datetime">{{ message.timestamp }}</div>
                </div>


                <p class="message">{{ message.message }}</p>
              </div>
            </div>

         </ng-container>
    </div>
    <form class="send-message-form" (ngSubmit)="sendMessage()" #chatForm="ngForm">
        <div>
            <input type="text" name="message" [(ngModel)]="message" placeholder="Your message" required>
            <button type="submit">Send</button>
        </div>
    </form>
</div>

Startup.cs

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SpaServices.AngularCli;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

using ProjectConker.Models;
using ProjectConker.Roadmaps;
using ProjectConker.Searching;

namespace ProjectConker
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

            // In production, the Angular files will be served from this directory
            services.AddSpaStaticFiles(configuration =>
            {
                configuration.RootPath = "ClientApp/dist";
            });

            services.AddHttpClient();

            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

            services.AddCors(options => options.AddPolicy("CorsPolicy", 
            builder => 
            {
                builder.AllowAnyMethod().AllowAnyHeader()
                       .WithOrigins("*")
                       .AllowCredentials();
            }));

            services.AddSignalR();

            services.AddEntityFrameworkSqlServer();

           // services.AddIdentity<IdentityUser, IdentityRole>();

            services.AddDbContext<ConkerDbContext>(
    options => options.UseQueryTrackingBehavior(QueryTrackingBehavior.TrackAll));

            services.AddScoped<SearchEngine>();
            services.AddTransient<RoadmapService>();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }

            // app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseSpaStaticFiles();

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller}/{action=Index}/{id?}");
            });

            app.UseSpa(spa =>
            {
                // To learn more about options for serving an Angular SPA from ASP.NET Core,
                // see https://go.microsoft.com/fwlink/?linkid=864501

                spa.Options.SourcePath = "ClientApp";

                if (env.IsDevelopment())
                {
                    spa.UseAngularCliServer(npmScript: "start");
                }
            });

            app.UseSignalR(routes =>
            {
                routes.MapHub<ChatHub>("/api/chat");
            });
        }
    }
}
C:\Users\wasii\Documents\CodingProjects\ProjectConker\ClientApp>ng version
Your global Angular CLI version (8.3.5) is greater than your local
version (6.0.8). The local Angular CLI version is used.

To disable this warning use "ng config -g cli.warnings.versionMismatch false".

     _                      _                 ____ _     ___
    / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
   / △ \ | '_ \ / _` | | | | |/ _` | '__|   | |   | |    | |
  / ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | |
 /_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|
                |___/


Angular CLI: 6.0.8
Node: 10.16.3
OS: win32 x64
Angular: 6.1.10
... animations, common, compiler, compiler-cli, core, forms
... http, platform-browser, platform-browser-dynamic
... platform-server, router

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.6.8
@angular-devkit/build-angular     0.6.8
@angular-devkit/build-optimizer   0.6.8
@angular-devkit/core              0.6.8
@angular-devkit/schematics        0.6.8
@angular/cli                      6.0.8
@angular/language-service         6.0.5
@ngtools/webpack                  6.0.8
@schematics/angular               0.6.8
@schematics/update                0.6.8
rxjs                              6.2.1
typescript                        2.7.2
webpack                           4.8.3
C:\Users\wasii\Documents\CodingProjects\ProjectConker>dotnet --info
.NET Core SDK (reflecting any global.json):
 Version:   2.2.402
 Commit:    c7f2f96116

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.18362
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Program Files\dotnet\sdk\2.2.402\

Host (useful for support):
  Version: 2.2.7
  Commit:  b1e29ae826

.NET Core SDKs installed:
  2.2.402 [C:\Program Files\dotnet\sdk]

.NET Core runtimes installed:
  Microsoft.AspNetCore.All 2.2.7 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.App 2.2.7 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 2.2.7 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]

To install additional .NET Core runtimes or SDKs:
  https://aka.ms/dotnet-download

1 Ответ

1 голос
/ 20 сентября 2019

Давайте рассмотрим ваш ChatComponent компонент, он инициализируется и пытается установить соединение с концентратором.Его ngOnInit() возвращает немедленно после того, как он связывает обработчик события для ReceiveMessage.

  ngOnInit() {
    ...
    this.hubConnection = new HubConnectionBuilder().withUrl(...).build();
    this.hubConnection
      .start()
      .then(() => console.log('Connection started!'))
      .catch(err => console.log('Error while establishing connection :('));
    this.hubConnection.on('ReceiveMessage', ...);
  }

Обратите внимание, что подключение к концентратору займет некоторое время.Если вы попытаетесь отправить сообщения на сервер до того, как будет установлено соединение , произойдет сбой.

Как исправить:

Создайте thenable, чтобы обеспечить соединение

  <b>private thenable: Promise<void></b>

  ngOnInit() {
    ...
    this.hubConnection = new HubConnectionBuilder().withUrl(...).build();
    <b>this.start()</b>
    this.hubConnection.on('ReceiveMessage', ...);
  }

  private start() {
    <b>this.thenable = this.hubConnection.start();</b>
    <b>this.thenable</b>
      .then(() => console.log('Connection started!'))
      .catch(err => console.log('Error while establishing connection :('));
  }

Когда бы вы ни захотели связаться с концентратором, вызывайте по thenable в стиле обещания.Например, ваш sendMessage() должен быть изменен следующим образом:

public sendMessage(): void {
    <b>this.thenable.then(() =>{</b>
        var today = new Date();
        this.messageData = ...
        this.hubConnection
           .invoke('SendToAll', this.author, this.messageData)
           .catch(err => console.error(err));
           this.message = '';
    <b>});</b>
}

[Обновить]

В вашем файле есть две другие ошибкикод:

  1. Вы зарегистрировали промежуточное программное обеспечение SignalR после промежуточного программного обеспечения Spa.Имейте в виду, что UseSpa() следует использовать в качестве промежуточного программного обеспечения.Вы должны вызвать UseSignalR() до UseSpa():

    <b>app.UseSignalR(routes =>
    {
        routes.MapHub<ChatHub>("/api/chat");
    });</b>
    
    app.UseMvc(routes =>
    {
        ...
    });
    
    app.UseSpa(spa =>
    {
        ...
    });
    
    <strike>app.UseSignalR(routes =>                        </strike>
    <strike>{                                               </strike>
    <strike>    routes.MapHub<ChatHub>("/api/chat");  </strike>
    <strike>});                                             </strike>
    
  2. Если вы подключаетесь к тому же серверу, избегайте использования жестко заданного URL:

    this.hubConnection = new HubConnectionBuilder().withUrl("<strike>http://localhost:5000</strike>/api/chat", {
          skipNegotiation: true,
          transport: HttpTransportType.WebSockets
        }).build();
    

    В противном случае происходит сбой при использовании другого порта / протокола.

...