We have migrated from .NET framework to .NET 6, however after conversion the reference libraries like "Microsoft.Owin.Security.OAuth" are not supported so I'm not able to use "OAuthAuthorizationServerProvider", we need the custom provider to validate credentials against AD, could you please help how to achieve the same in .NET core, same applies for Refresh token.
Apart from that, is OWIN cross platform? if not, what is the latest or widely used authentication mechanism?
public class AuthorizationProvider : OAuthAuthorizationServerProvider
{
public AuthorizationProvider()
{
// Code
}
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
// token endpoint is called from configuration service and ui.
// source parameter added to identify from where endpoint is called
var source = context.Parameters.Where(f => f.Key == "source").Select(f => f.Value).SingleOrDefault();
if (source != null && !string.IsNullOrEmpty(source[0]))
{
context.OwinContext.Set<string>("source", source[0]);
}
}
public class RefreshTokenProvider : IAuthenticationTokenProvider
{
private static ConcurrentDictionary<string, AuthenticationTicket> _refreshTokens = new ConcurrentDictionary<string, AuthenticationTicket>();
/// <summary>
/// There are two create methods in this class as interface expects both to be implemented
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public async Task CreateAsync(AuthenticationTokenCreateContext context)
{
Create(context);
}
}
Related
I have been introduced to an already existing C# ASP.Net Web API project a week ago. It returns all the data in JSON and Pascal Case, and this data is used by websites using React.Js which are case sensitive.
During the last week, after a commit that changed litteraly nothing on the API project (it only added translations for the Web Client project in the solution), suddenly the project started returning JSON in Camel case and not in Pascal Case anymore.
The problem is not like this post, I don't send to the API camel instead of pascal, the API sends camel instead of pascal.
I've been searching how to fix it but there are two specifities to the project that makes it difficult to find an answer :
The project uses ASP.Net and not ASP.Net Core, making posts like this or this not helpful
The project uses NancyFx 2.0.0, so it doesn't have any starting file (like the startup class in core projects, or .asax file) but uses a custom bootstrapper (see code down below)
Bootstrapper
public class AppBootstrapper : DefaultNancyBootstrapper
{
protected override void ApplicationStartup(TinyIoCContainer container, IPipelines pipelines)
{
log4net.Config.XmlConfigurator.Configure();
base.ApplicationStartup(container, pipelines);
pipelines.BeforeRequest.AddItemToStartOfPipeline(ctx =>
{
if (ctx != null)
{
Log.Request(ctx.Request.GetHashCode(), ctx.Request.Method, ctx.Request.Path, ctx.Request.UserHostAddress, ctx.Request.Headers.UserAgent);
}
return null;
});
pipelines.AfterRequest.AddItemToEndOfPipeline(ctx =>
{
if (ctx != null)
{
Log.Response(ctx.Request.GetHashCode(), ctx.Response.StatusCode);
}
});
}
protected override void RequestStartup(TinyIoCContainer container, IPipelines pipelines, NancyContext context)
{
pipelines.AfterRequest.AddItemToEndOfPipeline(ctx =>
{
ctx.Response.WithHeader("Access-Control-Allow-Origin", "*")
.WithHeader("Access-Control-Allow-Methods", "POST,GET,PUT,DELETE,HEAD,OPTIONS")
.WithHeader("Access-Control-Allow-Headers", "Accept, Origin, Content-type, Authorization");
});
// Gzip management, useless for this post
}
JsonSerializer
internal class JsonNetSerializer : ISerializer
{
private readonly JsonSerializer _serializer;
/// <summary>
/// Initializes a new instance of the <see cref="JsonNetSerializer"/> class.
/// </summary>
public JsonNetSerializer()
{
_serializer = JsonSerializer.CreateDefault();
}
/// <summary>
/// Initializes a new instance of the <see cref="JsonNetSerializer"/> class,
/// with the provided <paramref name="serializer"/>.
/// </summary>
/// <param name="serializer">Json converters used when serializing.</param>
public JsonNetSerializer(JsonSerializer serializer)
{
_serializer = serializer;
}
/// <summary>
/// Whether the serializer can serialize the content type
/// </summary>
/// <param name="mediaRange">Content type to serialise</param>
/// <returns>True if supported, false otherwise</returns>
public bool CanSerialize(MediaRange mediaRange)
{
return JsonHelpers.IsJsonType(mediaRange);
}
/// <summary>
/// Gets the list of extensions that the serializer can handle.
/// </summary>
/// <value>An <see cref="IEnumerable{T}"/> of extensions if any are available, otherwise an empty enumerable.</value>
public IEnumerable<string> Extensions
{
get { yield return "json"; }
}
/// <summary>
/// Serialize the given model with the given contentType
/// </summary>
/// <param name="mediaRange">Content type to serialize into</param>
/// <param name="model">Model to serialize</param>
/// <param name="outputStream">Output stream to serialize to</param>
/// <returns>Serialised object</returns>
public void Serialize<TModel>(MediaRange mediaRange, TModel model, Stream outputStream)
{
using (var writer = new JsonTextWriter(new StreamWriter(new UnclosableStreamWrapper(outputStream))))
{
_serializer.Serialize(writer, model);
}
}
}
I have looked for solutions and so long I've found some sites talking about Owin, but it seems that I have to use a owin-based server (like Nowin) to host the ASP.Net application. The problem is that I have literally never used/heard about it and I lack of time to learn how to use it. On top of that I'm not sure at all that Nowin's Start<TContext>() function will be useful to modify the API's return formatting...
Every other solution I've found was leading to ASP.Net Core technology, but nothing for ASP.Net
I am doing a migration and have encountered an exception. Autofac can resolve my service from an instance of a service provider, but cannot get it in my controller at the time of the request.
Exception: Castle.DynamicProxy.ProxyGe
nerationException: This is a DynamicProxy2 error: Target type for the proxy implements Castle.DynamicProxy.IP
roxyTargetAccessor which is a DynamicProxy infrastructure interface and you should never implement it yoursel
f. Are you trying to proxy an existing proxy?
My AutoregistrableModule looks like that:
public class AutoregisterableModule : Autofac.Module
{
private readonly string _nameFilter;
/// <summary>
/// Default ctor
/// </summary>
/// <param name="nameFilter">Load will only search assemblies with names that contains filter</param>
public AutoregisterableModule(string nameFilter)
{
_nameFilter = nameFilter;
}
/// <summary>
/// Register's dependencies
/// </summary>
protected override void Load(ContainerBuilder builder)
{
var assemblies = new List<Assembly>();
var dependencies = DependencyContext.Default.RuntimeLibraries.Where(x => x.Name.Contains(_nameFilter));
foreach (var library in dependencies)
{
var assembly = Assembly.Load(new AssemblyName(library.Name));
assemblies.Add(assembly);
}
builder.Register(c => new LogInterceptor()).InstancePerLifetimeScope();
var isProd = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Production";
var containerBuilder = builder.RegisterAssemblyTypes(assemblies.ToArray())
.Where(TypesToRegisterFilter)
.PreserveExistingDefaults()
.AsImplementedInterfaces();
if (!isProd)
{
containerBuilder.EnableInterfaceInterceptors();
}
base.Load(builder);
}
private static bool TypesToRegisterFilter(Type type)
{
return !type.IsSubclassOf(typeof(SwaggerConfigureOptions)) && !typeof(BackgroundService).IsAssignableFrom(type);
}
}
If I remove that row all works well(except of my LoggerInterceptor :D)
containerBuilder.EnableInterfaceInterceptors();
My service looks like
[Intercept(typeof(LogInterceptor))]
public class CategoriesService : ICategoriesService
{
// some code here
}
I tried to fix it by downgranding Autofac.Extensions.DependencyInjection package from 6.0.0 to 5.0.1 as were suggested there but it didn't help.
You can find full Stacktrace there https://pastebin.com/YCAhLQv0 .
So the question is how can I fix the exception and keep my interceptor working?
Fixed by raising Autofac.Extras.DynamicProxy package version from 4.5.0 to 5.0.0.
Hope it may help someone.
Trying to use:
Startup.cs
public void ConfigureServices(IServiceCollection services) {
services.AddHostedService<LifetimeEvents>();
.
.
.
}
where the LifeTimeEvents class inherits from IHostedService. I get this error:
'IServiceCollection' does not contain a definition for 'AddHostedService' and no extension method 'AddHostedService' accepting a first argument of type 'IServiceCollection' could be found (are you missing a using directive or an assembly reference?)
I can't seem to find the proper namespace to use or nuget package to include to get this working, but it worked out of the box in .NET Core 2.1, is this just not available in .NET Core 2.0? Is there any way to get it working?
UPDATE:
As a workaround I changed my code to use:
Startup.cs
public void ConfigureServices(IServiceCollection services) {
services.AddSingleton<LifetimeEvents>();
.
.
.
}
public void Configure(IApplicationBuilder appBuilder, IHostingEnvironment envHost, LifetimeEvents appEvents) {
appEvents.StartAsync(new CancellationToken(false));
.
.
.
}
and that seems to have done the job. Doesn't answer my original question, and I'm not sure how "best practices" it is, but it did get me moving refactoring this .NET Core 2.0 app.
is this just not available in .NET Core 2.0?
ServiceCollectionHostedServiceExtensions.AddHostedService(IServiceCollection) Method as shown in the API reference
Applies to
ASP.NET Core
2.1
However the source code is available on GitHub. You can easily check it out there and copy a local version to your 2.0 project
namespace Microsoft.Extensions.DependencyInjection
{
public static class ServiceCollectionHostedServiceExtensions
{
/// <summary>
/// Add an <see cref="IHostedService"/> registration for the given type.
/// </summary>
/// <typeparam name="THostedService">An <see cref="IHostedService"/> to register.</typeparam>
/// <param name="services">The <see cref="IServiceCollection"/> to register with.</param>
/// <returns>The original <see cref="IServiceCollection"/>.</returns>
public static IServiceCollection AddHostedService<THostedService>(this IServiceCollection services)
where THostedService : class, IHostedService
=> services.AddTransient<IHostedService, THostedService>();
}
}
Source code
Ideally you could just update the project to 2.1 where the extension becomes available.
I believe this is a duplicate question to what I've answered before.
Where am I supposed to start persistent background tasks in ASP.NET Core?
Below is the answer, copy + pasted.
I believe you're looking for this
https://blogs.msdn.microsoft.com/cesardelatorre/2017/11/18/implementing-background-tasks-in-microservices-with-ihostedservice-and-the-backgroundservice-class-net-core-2-x/
And i did a 2 hour self-proclaimed-award-winning hackathon against myself to learn abit of that.
https://github.com/nixxholas/nautilus
You can refer the injections here and implement the abstracts from there too.
Many MVC projects are not really required to operate persistent background tasks. This is why you don't see them baked into a fresh new project via the template. It's better to provide developers an interface to tap on and go ahead with it.
Also, with regards to opening that socket connection for such background tasks, I have yet to establish a solution for that. As far as I know/did, I was only able to broadcast payload to clients that are connected to my own socketmanager so you'll have to look elsewhere for that. I'll definitely beep if there is anything regarding websockets in an IHostedService.
Ok anyway here's what happens.
Put this somewhere in your project, its more of an interface for you to overload with to create your own task
/// Copyright(c) .NET Foundation.Licensed under the Apache License, Version 2.0.
/// <summary>
/// Base class for implementing a long running <see cref="IHostedService"/>.
/// </summary>
public abstract class BackgroundService : IHostedService, IDisposable
{
protected readonly IServiceScopeFactory _scopeFactory;
private Task _executingTask;
private readonly CancellationTokenSource _stoppingCts =
new CancellationTokenSource();
public BackgroundService(IServiceScopeFactory scopeFactory) {
_scopeFactory = scopeFactory;
}
protected abstract Task ExecuteAsync(CancellationToken stoppingToken);
public virtual Task StartAsync(CancellationToken cancellationToken)
{
// Store the task we're executing
_executingTask = ExecuteAsync(_stoppingCts.Token);
// If the task is completed then return it,
// this will bubble cancellation and failure to the caller
if (_executingTask.IsCompleted)
{
return _executingTask;
}
// Otherwise it's running
return Task.CompletedTask;
}
public virtual async Task StopAsync(CancellationToken cancellationToken)
{
// Stop called without start
if (_executingTask == null)
{
return;
}
try
{
// Signal cancellation to the executing method
_stoppingCts.Cancel();
}
finally
{
// Wait until the task completes or the stop token triggers
await Task.WhenAny(_executingTask, Task.Delay(Timeout.Infinite,
cancellationToken));
}
}
public virtual void Dispose()
{
_stoppingCts.Cancel();
}
}
Here's how you can actually use it
public class IncomingEthTxService : BackgroundService
{
public IncomingEthTxService(IServiceScopeFactory scopeFactory) : base(scopeFactory)
{
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
using (var scope = _scopeFactory.CreateScope())
{
var dbContext = scope.ServiceProvider.GetRequiredService<NautilusDbContext>();
Console.WriteLine("[IncomingEthTxService] Service is Running");
// Run something
await Task.Delay(5, stoppingToken);
}
}
}
}
If you noticed, there's a bonus there. You'll have to use a servicescope in order to access db operations because its a singleton.
Inject your service in
// Background Service Dependencies
services.AddSingleton<IHostedService, IncomingEthTxService>();
I'm using Web API 2 with Ninject and i'm getting the following error when i've got multiple parallel HTTP calls.
A second operation started on this context before a previous asynchronous operation completed. Use 'await' to ensure that any asynchronous operations have completed before calling another method on this context. Any instance members are not guaranteed to be thread safe.
I didn't get this error before, all the code that retrieves the data from the database is async so i'm thinking its a Ninject scope issue.
NinjectWebCommon
kernel.BindHttpFilter<MyAuthenticateFilter>(FilterScope.Action);
// Database context
kernel.Bind<IUnitOfWorkAsyncFactory>().To<UnitOfWorkAsyncFactory>().InRequestScope();
kernel.Bind<IUnitOfWorkAsync>().To<UnitOfWork>().InRequestScope();
kernel.Bind<IDataFactory>().To<DataFactory>().InRequestScope();
All the Application and domain handlers are also async and make use of the same DataFactory and UnitOfWorkAsyncFactory.
Seems like there's a threading issue with the IAuthenticationFilter.
The factory pattern used for the DbContext.
public class DataFactory : Disposable, IDataFactory
{
private MyContext DbContext { get; set; }
public IDataContextAsync GetDataContext()
{
return DbContext ?? (DbContext = new MyContext());
}
public void AfterDispose()
{
DbContext = null;
}
public DataFactory()
{
}
public DataFactory(MyContext context)
{
DbContext = context;
}
}
I remember some time ago having issues with filter injection in WebApi and scopes being lost.
As far as I remember using this implementation of IDependencyResolver (can not remember where I got it) made the issue go away.
using System.Web.Http.Dependencies;
using global::Ninject.Syntax;
public class DependencyResolverWebApiNinject : DependencyScopeWebApiNinject, IDependencyResolver
{
public DependencyResolverWebApiNinject(IResolutionRoot resolutionRoot)
: base(resolutionRoot)
{
}
public virtual IDependencyScope BeginScope()
{
return this;
}
}
Where DependencyScopeWebApiNinject is :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http.Dependencies;
using global::Ninject;
using global::Ninject.Infrastructure.Disposal;
using global::Ninject.Parameters;
using global::Ninject.Syntax;
public class DependencyScopeWebApiNinject : DisposableObject, IDependencyScope
{
/// <summary>
/// Initializes a new instance of the <see cref="DependencyScopeWebApiNinject"/> class.
/// </summary>
/// <param name="resolutionRoot">The resolution root.</param>
public DependencyScopeWebApiNinject(IResolutionRoot resolutionRoot)
{
this.ResolutionRoot = resolutionRoot;
}
/// <summary>
/// Gets the resolution root.
/// </summary>
/// <value>The resolution root.</value>
protected IResolutionRoot ResolutionRoot
{
get;
private set;
}
/// <summary>
/// Gets the service of the specified type.
/// </summary>
/// <param name="serviceType">The type of the service.</param>
/// <returns>The service instance or <see langword="null"/> if none is configured.</returns>
public object GetService(Type serviceType)
{
var request = this.ResolutionRoot.CreateRequest(serviceType, null, new Parameter[0], true, true);
return this.ResolutionRoot.Resolve(request).SingleOrDefault();
}
/// <summary>
/// Gets the services of the specifies type.
/// </summary>
/// <param name="serviceType">The type of the service.</param>
/// <returns>All service instances or an empty enumerable if none is configured.</returns>
public IEnumerable<object> GetServices(Type serviceType)
{
return this.ResolutionRoot.GetAll(serviceType).ToList();
}
}
hope this will help
I have been reading the official Session and application state documentation and have stumbled upon the following paragraph:
Loading Session asynchronously
The default session provider in ASP.NET Core loads the session record
from the underlying IDistributedCache store asynchronously only if the
ISession.LoadAsync method is explicitly called before the TryGetValue,
Set, or Remove methods. If LoadAsync is not called first, the
underlying session record is loaded synchronously, which could
potentially impact the ability of the app to scale.
To have applications enforce this pattern, wrap the
DistributedSessionStore and DistributedSession implementations with
versions that throw an exception if the LoadAsync method is not called
before TryGetValue, Set, or Remove. Register the wrapped versions in
the services container.
The wrapping itself is not an issue for me, but in order to implement it, I need:
Reference to the original implementation
Registering the wrapped version
Currently, I have created the following wrapper class:
public class WrappedDistributedSession : ISession
{
private DistributedSession _service;
private bool loaded = false;
public WrappedDistributedSession(DistributedSession service)
{
_service = service;
}
public bool IsAvailable => _service.IsAvailable;
public string Id => _service.Id;
public IEnumerable<string> Keys => _service.Keys;
public void Clear() => _service.Clear();
public Task CommitAsync() => _service.CommitAsync();
public Task LoadAsync()
{
loaded = true;
return _service.LoadAsync();
}
public void Remove(string key)
{
if(loaded)
{
_service.Remove(key);
} else
{
throw new Exception();
}
}
public void Set(string key, byte[] value)
{
if (loaded)
{
_service.Set(key, value);
}
else
{
throw new Exception();
}
}
public bool TryGetValue(string key, out byte[] value)
{
if (loaded)
{
return _service.TryGetValue(key, out value);
}
else
{
throw new Exception();
}
}
}
And I have registered it in the Startup.ConfigureServices
services.AddScoped<ISession, WrappedDistributedSession>();
Obviously, since I am writing this question, my solution does not work. Where did I go wrong and how does one "Register the wrapped versions in the services container"?
Use at your risk. This seems to work in Configure method just after sessions.
This solution is an adaptation from this unit test:
https://github.com/dotnet/aspnetcore/blob/cd0eab88eaa230fa276c27ab5dc71ea267efe14f/src/Middleware/Session/test/SessionTests.cs#L654-L656
app.UseSession();
app.Use(async (context, next) =>
{
await context.Session.LoadAsync();
await next();
});
Or as a more qualified wrapper extension:
public static class SesssionAsyncExtensions
{
/// <summary>
/// Have sessions be asyncronous. This adaptation is needed to force the session provider to use async calls instead of syncronous ones for session.
/// Someone surprisingly for something that seems common, Microsoft didn't make this aspect super nice.
/// </summary>
/// <param name="app">App builder instance.</param>
/// <returns>App builder instance for chaining.</returns>
/// <remarks>
/// From Microsoft Documentation (https://learn.microsoft.com/en-us/aspnet/core/fundamentals/app-state?view=aspnetcore-5.0):
/// The default session provider in ASP.NET Core will only load the session record from the underlying IDistributedCache store asynchronously if the
/// ISession.LoadAsync method is explicitly called before calling the TryGetValue, Set or Remove methods.
/// Failure to call LoadAsync first will result in the underlying session record being loaded synchronously,
/// which could potentially impact the ability of an application to scale.
///
/// See also:
/// https://github.com/dotnet/aspnetcore/blob/d2a0cbc093e1e7bb3e38b55cd6043e4e2a0a2e9a/src/Middleware/Session/src/DistributedSession.cs#L268
/// https://github.com/dotnet/AspNetCore.Docs/issues/1840#issuecomment-454182594
/// https://bartwullems.blogspot.com/2019/12/aspnet-core-load-session-state.html
/// </remarks>
public static IApplicationBuilder UseAsyncSession(this IApplicationBuilder app)
{
app.UseSession();
app.Use(async (context, next) =>
{
await context.Session.LoadAsync();
await next();
});
return app;
}
}
It seems you need to implement ISessonStore too (which is actually mentioned in the documentation you quoted), as it's the only one registered in AddSession extension method.
public static IServiceCollection AddSession(this IServiceCollection services)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
services.AddTransient<ISessionStore, DistributedSessionStore>();
services.AddDataProtection();
return services;
}
ISessionStore (and hence DistributedSessionStore) has a Create (see source) method which returns ISession. Here you need to return your custom implementation.
https://github.com/aspnet/Session/blob/rel/1.1.0/src/Microsoft.AspNetCore.Session/SessionServiceCollectionExtensions.cs#L27-L29
Then you can add before AddSession with
services.AddTransient<ISessionStore, AsyncDistributedSessionStore>();