I am converting a .Net Framework 4.7.2 WebApi to asp.net Core3.0 and need to use Http.Sys with its listener set to an item in appsettings.json - appsettings

I have seen a number of solutions for .Net Core 2 that I cannot seem to translate to 3.0. In most cases they do not use the Templated Program and Startup, but are purpose-built.
I use the WebApi template supplied in Visual Studio 2019 Community (latest patches).
In Core 3.0, the Configuration appsettings.json is automatically loaded and via DI in startup, is available to the rest of my code.
I need a couple of the items from appsettings.json, Configuration.GetSection("OrAppSettings")["OrSvrBaseUrl"]
Configuration.GetSection("OrAppSettings")["OrSvrUrlPort"] to be available in order to set the Http.sys Options.UrlPrefixes variable serverName in the Program.cs file.
I use Http.sys, as the Apis will be running in internal servers, as self-hosted, and using Kestrel, would only run at localhost. Therefore they will be unreachable unless Kestrel is run behind IIS. Http.sys can run as a self-hosted service, reachable across the LAN.
The apis etc are part of a larger solution offered to many of our customers and must fit into a variety of scenarios over which we have no real control.
I probably also need the same appsettings items for configuring Swagger, but that will be done in Startup.
I also need to use appsettings.json to provide configuration in the WebAPI client asp.net programs, but I have that covered, since DI from Startup is all I need there.
My appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"OrAppSettings": {
"ClientName": "some customer name",
"AsoAka": "mwp",
"AsoLocation": "shadow-10",
"AsoRouting": "unauthenticated",
"AsoClientType": "3",
"AsoClientUserId": "0",
"AsoClientUserName": "shadow-10\\ingres",
"AsoClientIpAddress": "",
"ORSvrBaseUrl": "http://shadow-10",
"ORSvrUrlPort": "5003",
"EnableSwaggerUI": "true"
},
"AllowedHosts": "*"
}
My Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Server.HttpSys;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.EventLog;
namespace MwpOrApiCore30
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static string serverName = "http://localhost:5005";
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
// Services
.ConfigureServices(services =>
{
services.Configure<EventLogSettings>(config =>
{
config.LogName = "Mwp Or Api";
config.SourceName = "MwpOrApi Source";
});
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseHttpSys(options =>
{
options.AllowSynchronousIO = true;
options.Authentication.Schemes = AuthenticationSchemes.None;
options.Authentication.AllowAnonymous = true;
options.MaxConnections = null;
options.MaxRequestBodySize = 30000000;
//options.UrlPrefixes.Add("http://shadow-10:5005");
options.UrlPrefixes.Add(serverName);
});
webBuilder.UseStartup<Startup>();
})
//.ConfigureWebHost(config =>
//{
// config.UseKestrel().UseUrls("http://0.0.0.0:5003");
//})
.UseWindowsService();
}
}
My MODIFIED Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Server.HttpSys;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.EventLog;
namespace MwpOrApiCore30
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static string serverName = "http://localhost:5005";
public static IHostBuilder CreateHostBuilder(string[] args)
{
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
serverName = configuration.GetSection("OrAppSettings")["ORSvrBaseUrl"];
serverName += ":" + configuration.GetSection("OrAppSettings")["ORSvrUrlPort"];
return Host.CreateDefaultBuilder(args)
.UseWindowsService()
. ConfigureServices(services =>
{
// services.AddHostedService<worker>();
})
// Services
.ConfigureServices(services =>
{
services.Configure<EventLogSettings>(config =>
{
config.LogName = "Mwp Or Api";
config.SourceName = "MwpOrApi Source";
});
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseHttpSys(options =>
{
options.AllowSynchronousIO = true;
options.Authentication.Schemes = AuthenticationSchemes.None;
options.Authentication.AllowAnonymous = true;
options.MaxConnections = null;
options.MaxRequestBodySize = 30000000;
//options.UrlPrefixes.Add("http://shadow-10:5005");
options.UrlPrefixes.Add(serverName);
});
webBuilder.UseStartup<Startup>();
});
}
}
}
My Startup.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.OpenApi.Models;
namespace MwpOrApiCore30
{
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();
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo
{
Title = "Mwp OR WebApi",
Version = "v1" ,
Description = "An ASP.NET CORE 3.0 Web Api for MWP OpenRoad Server",
Contact = new OpenApiContact
{
Name = "xxxxxx",
Email = "someone#someplace.com.au"
});
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
// Enable middleware to serve generated Swagger as a JSON endpoint.
app.UseSwagger();
// Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.),
// specifying the Swagger JSON endpoint.
string enableSwaggerUi = Configuration.GetSection("OrAppSettings").GetValue<string>("EnableSwaggerUI");
if (enableSwaggerUi == "true")
{
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "Mwp OR API V1");
});
}
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}

Related

Lamar with ASP.NET Core 6.0 and controller registration

I am trying to properly structure my ASP.NET Core 6.0 service registrations and therefore would like to move the registration into its own class.
Unfortunately, the code below doesn't work. It seems the controllers are not registered as swagger complains about No operations defined in spec!. If I move the call to registry.AddControllers() back to my ConfigureRegistry method, it works.
What am I doing wrong here?
var builder = WebApplication.CreateBuilder(args);
ConfigureConfiguration(builder.Configuration);
ConfigureRegistry(builder.Host, builder.Configuration);
var app = builder.Build();
ConfigureMiddleware(app, app.Services, app.Environment);
ConfigureEndpoints(app, app.Services, app.Environment);
app.Run();
void ConfigureConfiguration(ConfigurationManager configuration)
{
}
void ConfigureRegistry(ConfigureHostBuilder host, ConfigurationManager config)
{
host.UseLamar((context, registry) =>
{
// registry.AddControllers();
// registry.AddEndpointsApiExplorer();
// registry.AddSwaggerGen();
// registry.AddAutoMapper(typeof(Program));
registry.IncludeRegistry<WebRegistry>();
// ...
registry.IncludeRegistry<ApplicationRegistry>();
registry.IncludeRegistry<InfrastructureRegistry>();
});
}
void ConfigureMiddleware(IApplicationBuilder app, IServiceProvider services, IWebHostEnvironment environment)
{
if (environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.UseRouting();
}
void ConfigureEndpoints(IEndpointRouteBuilder app, IServiceProvider services, IWebHostEnvironment environment)
{
app.MapControllers();
}
public class WebRegistry : ServiceRegistry
{
public WebRegistry()
{
this.AddControllers();
this.AddEndpointsApiExplorer();
this.AddSwaggerGen();
this.AddAutoMapper(typeof(Program));
For<ICategoryViewService>().Use<CategoryViewService>();
}
}

OData Controller withing Asp.Net Core MVC application

I'm working on a project in ASP .NET Core 3.1 MVC now I want to add some API controllers to return list of objects.
For this I want to use OData Controller version 8.0.0 so I can get quarriable data to improve performance on large data tables
I'm new in ASP .NET Core and OData. can anybody explain how to configure my project's Startup file so I can run both MVC and OData controllers same time.
Kindly share some example code
Firstly, you have a MVC project, since MVC project can also expose API, so OData should also work for MVC project. Firstly, assuming you've integrate ef core and in my workaround, I followed this document to create database and data management view for a model.
Then let's add OData. Install this nuget package: Microsoft.AspNetCore.OData, modify your startup.cs file, please see the Configuration and GetEdmModel method.
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.EntityFrameworkCore;
using WebMvcNet5.Data;
using WebMvcNet5.Models;
using Microsoft.OData.ModelBuilder;
using Microsoft.AspNetCore.OData;
using Microsoft.OData.Edm;
namespace WebMvcNet5
{
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.AddControllersWithViews();
services.AddControllers().AddOData(opt => opt.EnableQueryFeatures().AddRouteComponents("odata", GetEdmModel()));
services.AddDbContext<WebMvcNet5Context>(options =>
options.UseSqlServer(Configuration.GetConnectionString("WebMvcNet5Context")));
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/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.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
private static IEdmModel GetEdmModel()
{
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
//My model is Movie, and what I set "GetMovie" here means I need to create a controller named "GetMovieController"
builder.EntitySet<Movie>("GetMovie");
return builder.GetEdmModel();
}
}
}
Then this is my controller:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.OData.Query;
using WebMvcNet5.Data;
namespace WebMvcNet5.Controllers
{
[Route("odata/[Controller]")]
public class GetMovieController : Controller
{
private readonly WebMvcNet5Context _context;
public GetMovieController(WebMvcNet5Context context)
{
_context = context;
}
[EnableQuery]
public IActionResult Get()
{
return Ok(_context.Movie);
}
}
}
My test result:
I have managed to fix my issue to run Web Application which exposes OData APIs
Issue was in Startup.cs file
I'm using Asp.Net Core 3.1 and Microsoft.AspNetCore.OData v7.3.0
my Startup.cs file code is:
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.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<AppUser, AppRole>(opt =>
{
opt.User.RequireUniqueEmail = true;
})
//.AddDefaultUI(UIFramework.Bootstrap4)
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
//add services
services.RegisterServices();
services.AddScoped<ViewRendererService>();
services.AddMvc()
.AddMvcOptions(options => options.EnableEndpointRouting = false)
.AddNewtonsoftJson(options =>
{
options.SerializerSettings.ContractResolver = new Newtonsoft.Json.Serialization.DefaultContractResolver();
})
.SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
services.AddOData();
services.AddRouting();
services.AddControllersWithViews();
services.AddRazorPages();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ApplicationDbContext dataContext)
{
if (env.EnvironmentName == "Development")
{
dataContext.Database.Migrate();
app.UseDeveloperExceptionPage();
}
else
{
app.UseDeveloperExceptionPage();
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseAuthentication();
app.UseRequestLocalization();
app.UseMvc(routes =>
{
routes.Select().Filter().OrderBy().Expand().Count().SkipToken().MaxTop(null);
routes.MapODataServiceRoute("odata", "api", GetEdmModel());
routes.MapRoute(
name: "areas",
template: "{area:exists}/{controller=Home}/{action=Index}/{id?}"
);
routes.MapRoute(
name: "Finance",
template: "{area:exists}/{controller=Account}/{action=Index}/{id?}"
);
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
private static IEdmModel GetEdmModel()
{
var builder = new ODataConventionModelBuilder();
builder.EntitySet<Product>("ProductApi");
builder.EntitySet<ProductUOM>("ProductUomApi");
ActionConfiguration action = builder.EntityType<Product>().Action("GetUOM");
action.Parameter<long>("id");
action.ReturnsCollectionFromEntitySet<Product>("Product");
return builder.GetEdmModel();
}
}
Hope this will help others

Why MapFallbackToController is not working: HTTP 401 UNAUTHORIZED Asp.net Core

I finished my app and i want to publish it into web.
Working on core 3.1.1 + angular2.
I created Fallback controller for routes.
It seems MapFallbackToController is not working. I don't have acceses to these files because i'm unauthorized, but why?
When i do "dotnet run" my page is blank and in the console:
Everything worked perfect until i moved angular files(wwwroot) into API proj.
Startup.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using AutoMapper;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using RecipesApp.API.Controllers.Models.Data;
using RecipesApp.API.Data;
using RecipesApp.API.Helpers;
namespace RecipesApp.API
{
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.AddDbContext<DataContext>( x=> x.UseSqlite(Configuration.GetConnectionString("DefaultConnection")));
services.AddControllers().AddNewtonsoftJson(opt => {
opt.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
});
services.AddCors();
services.Configure<CloudinarySettings>(Configuration.GetSection("CloudinarySettings"));
services.AddAutoMapper(typeof(RecipesRepository).Assembly);
services.AddScoped<IAuthRepository, AuthRepository>();
services.AddScoped<IUserRepository, UserRepository>();
services.AddScoped<IRecipesRepository, RecipesRepository>();
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options => {
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII
.GetBytes(Configuration
.GetSection("AppSettings:Token").Value)),
ValidateIssuer = false,
ValidateAudience = false
};
});
services.AddScoped<LogUserActivity>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler(builder =>
{
builder.Run(async context =>
{
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
var error = context.Features.Get<IExceptionHandlerFeature>();
if (error != null)
{
context.Response.AddApplicationError(error.Error.Message);
await context.Response.WriteAsync(error.Error.Message);
}
});
});
}
// app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseCors(x => x.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapFallbackToController("Index", "Fallback");
});
}
}
}
My fallback class
public class Fallback : Controller
{
public IActionResult Index()
{
return PhysicalFile(Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "index.html"), "text/HTML");
}
}
}
Somewhere in your startup file, i think you have specified that before a request gets to a controller, an authorization is needed, hence the error. In your case, can you try putting the AllowAnonymous attribute in your Fallback file as this tells netcore to map back to the fallback controller in search for angular index.html file. So, something like this;
[AllowAnonymous]
public class Fallback : ControllerBase
{
public IActionResult Index()
{
return PhysicalFile(Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "index.html"), "text/HTML");
}
}
In your startup.cs file, inside your Configure() method, out the app.UseStaticFiles() after app.UseRouting(). That's all.

GraphQLAuthorize attribute not firing [graphql]

I am working on the qraphQL api and I am trying to use authorization attribute GraphQLAuthorize in GraphQL.Server.Authorization.AspNetCore; I have created policy in startup.cd configureService but not recognized by GraphQLAuthorize attribute.
The [GraphQLAuthorize(Policy = "AUTHORIZED")] is not working.
while the AuthorizeWith("AUTHORIZED") is working
using GraphQL.Repository.GraphQL.Types;
using GraphQL.Repository.Repositories;
using GraphQL.Types;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using GraphQL.Server.Authorization.AspNetCore;
namespace GraphQL.Repository.GraphQL
{
[GraphQLAuthorize(Policy = "AUTHORIZED")]
public class MenuQuery : ObjectGraphType
{
public MenuQuery(MenuRepository menuRepository)
{
Field<ListGraphType<NavigationMenuType>>(
"NavigationMenu",
arguments: new QueryArguments(new QueryArgument<NonNullGraphType<IdGraphType>> { Name = "applicationId" }),
resolve: context =>
{
var user = (ClaimsPrincipal)context.UserContext;
var applicationId = context.GetArgument<int>("applicationId");
return menuRepository.GetNavigationMenus(applicationId);
});
}
}
}
//startup.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
//using GraphQL;
using GraphQL.Server;
using Microsoft.EntityFrameworkCore;
using GraphQL.Repository.Entities;
using GraphQL.Repository.Repositories;
using GraphQL.Repository.GraphQL;
using GraphQL.Repository.GraphQL.Types;
using Microsoft.Extensions.DependencyInjection.Extensions;
using GraphQL.Server.Ui.GraphiQL;
using GraphQL.Server.Ui.Playground;
namespace GraphQL.Api
{
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.AddDbContext<MenuManagementDevContext>(options =>
options.UseSqlServer(Configuration["ConnectionStrings:CarvedRockContext"]));
services.AddScoped<MenuRepository>();
services.AddScoped<MenuQuery>();
services.AddScoped<NavigationMenuType>();
services.AddScoped<RoleNavigationMenuType>();
services.AddScoped<RoleType>();
services.AddScoped<IDependencyResolver>(s => new FuncDependencyResolver(s.GetRequiredService));
services.AddScoped<MenuSchema>();
services.AddGraphQL(o => { o.ExposeExceptions = true; })
.AddGraphQLAuthorization(options =>
{
options.AddPolicy("AUTHORIZED", p => p.RequireAuthenticatedUser());
})
.AddGraphTypes(ServiceLifetime.Scoped).AddUserContextBuilder(httpContext => httpContext.User)
.AddDataLoader()
.AddWebSockets();
services.AddCors();
}
// 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();
}
app.UseCors(builder =>
builder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod());
app.UseWebSockets();
app.UseGraphQLWebSockets<MenuSchema>("/graphql");
app.UseGraphQL<MenuSchema>();
app.UseGraphiQLServer(new GraphiQLOptions());
app.UseGraphQLPlayground(new GraphQLPlaygroundOptions());
}
}
}
Any help would be appreciated!

how to override SignalR methods in mvc 5

I am working on a asp.net mvc5 project and I want to implement chatroom with signalR So I got Microsoft.Aspnet.SignalR from nuget and I used a SignalR Hub class for hub and now i want to override OnDisconnected() method .but I get error
'ChatHub.OnDisconnected()': no suitable method found to override
I dont know how to solve this problem please help me
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.AspNet.SignalR;
using System.Collections.Concurrent;
using System.Threading.Tasks;
namespace WebApplication3.Hubs
{
public class ChatHub : Hub
{
public void Hello()
{
Clients.All.hello();
}
static ConcurrentDictionary<string, string> dic = new ConcurrentDictionary<string, string>();
public void Send(string name, string message)
{
Clients.All.broadcastMessage(name, message);
}
public void SendToSpecific(string name, string message, string to)
{
// Call the broadcastMessage method to update clients.
Clients.Caller.broadcastMessage(name, message);
Clients.Client(dic[to]).broadcastMessage(name, message);
}
public void Notify(string name, string id)
{
if (dic.ContainsKey(name))
{
Clients.Caller.differentName();
}
else
{
dic.TryAdd(name, id);
foreach (KeyValuePair<String, String> entry in dic)
{
Clients.Caller.online(entry.Key);
}
Clients.Others.enters(name);
}
}
public override Task OnDisconnected()
{
var name = dic.FirstOrDefault(x => x.Value == Context.ConnectionId.ToString());
string s;
dic.TryRemove(name.Key, out s);
return Clients.All.disconnected(name.Key);
}
}
}
For SignalR 2.1.0+, you need to use OnDisconected(bool stopCalled).
// Microsoft.AspNet.SignalR.Hub
// Summary:
// Called when a connection disconnects from this hub gracefully or due to a timeout.
//
// Parameters:
// stopCalled:
// true, if stop was called on the client closing the connection gracefully; false,
// if the connection has been lost for longer than the Microsoft.AspNet.SignalR.Configuration.IConfigurationManager.DisconnectTimeout.
// Timeouts can be caused by clients reconnecting to another SignalR server in scaleout.
//
// Returns:
// A System.Threading.Tasks.Task
public virtual Task OnDisconnected(bool stopCalled);

Resources