I ran into a problem configuring a custom asp.net membership service.
I've got an annoying message on application startup when binding modules, here it is :
this.Bind<RoleProvider>()
.ToConstant(Roles.Providers["SQLiteRoleProvider"]);
this.Bind<MembershipProvider>()
.ToConstant(Membership.Providers["SQLiteMembershipProvider"]);
This method cannot be called during the application's pre-start initialization stage.
At
>System.Web.dll!System.Web.Compilation.BuildManager.EnsureTopLevelFilesCompiled()
in {System.Web.Compilation.BuildManager} System.Web.Compilation.BuildManager
I've check a bunch of blogs and SO question like
ASP.NET: This method cannot be called during the application's pre-start initialization stage
.net console app lifecycle - working around a pre-start initialization error from BuildManager.GetReferencedAssemblies
http://weblogs.asp.net/leftslipper/archive/2010/07/28/migrating-asp-net-mvc-2-applications-to-asp-net-mvc-3-preview-1.aspx#7635403
also but haven't any success.
Has anyone encountered this error message before?
Changing the binding code will fix the problem.
this.Bind<RoleProvider>().ToProvider<SQLiteRoleProvider>();
this.Bind<MembershipProvider>().ToProvider<SQLiteMembershipProvider>();
Just make the SQLiteMembershipProvider and SQLiteRoleProvider implementing the IProvider.
If you postpone the initialization it's gonna get right.
I had huge problems with that too. Something about providers that doesn't work well with Ninject. I never figured it out. I decided to make it fixed rather than injected. I abstracted everything into a Service and made the Ninject bindings against this service class. I ended up with a Service that has hardcode use of my Entity Framework membership provider and if I need another provider I will have to implement another service that has that provider hardcoded.
Injection with a simple service class works but it does not with the ToConstant() direct binding to the provider.
public class AccountMembershipService : IMembershipService
{
private readonly MembershipProvider _provider;
private readonly IAccountRepository _accountRepository;
private readonly IFirmsRepository _firmsRepository;
private readonly IRepository<Client> _clientsRepository;
public AccountMembershipService(IAccountRepository accountRepository, IFirmsRepository firmRepository,
IRepository<Client> clientsRepository)
{
_provider = System.Web.Security.Membership.Providers["EfMembershipProvider"];
_accountRepository = accountRepository;
_firmsRepository = firmRepository;
_clientsRepository = clientsRepository;
}
...
global.asax.cs
Bind<IFormsAuthenticationService>().To<FormsAuthenticationService>();
Bind<IMembershipService>().To<AccountMembershipService>();
Bind<IAccountRepository>().To<EntityFrameworkAccountProvider>();
// never worked
//Bind<MembershipProvider>().ToConstant(System.Web.Security.Membership.Providers["EfMembershipProvider"]);
Related
I created a ASP.NET 6, Blazor Server-side project. I injected a logger to the WeatherForecastService classes. I created a library project, and referenced it from the ASP.NET project. I created a object in that library in the ASP.NET project and passed a logger.
If I start it in debug mode in Visual Studio, the log messages from both projects are printed in the Output panel. That is good, but what I what I want to do is, in addition to that (that is, not disabling the log output in the Output panel of VS), show the logs within my ASP.NET project. For example, there can be a "Logs" page.
Probably there is no easy way to send log messages to the client browser in real-time, so I am going to poll the server at every second for new log messages. To do that, I think I have to get notified whenever a log message happens in the ASP.NET project. Not just for the logs from the ASP.NET project itself, but from the referenced project, too, just like VS's Output panel. Can I do that?
ASP.NET 6, Blazor Server-side project
namespace BlazorApp1.Data
{
public class WeatherForecastService
{
private readonly ILogger _logger;
public WeatherForecastService(ILogger<WeatherForecastService> logger, IServiceProvider sp)
{
_logger = logger;
var d = new Dog(sp.GetRequiredService<ILogger<Dog>>());
logger.LogInformation("WeatherForecastService created.");
}
}
Referenced "library" project
using Microsoft.Extensions.Logging;
namespace ClassLibrary1
{
public class Dog
{
public Dog(ILogger<Dog> logger)
{
logger.LogInformation("Dog created.");
}
}
}
Depending on where are you logging you are ether pooling the file or the database. For referenced projects and logs in them you need to implement logger and actually log data to the same file. or different one, but in service you need to fetch all data from all the files.
As far as i know default logger that is logging to console is just for that. You need to ether implement your own logging library or you can import serilog or log4net. And insted of using default ILogger in the same way you use your implementation witch logs data to ether file or db.
Microsoft link for implementing logging provider https://learn.microsoft.com/en-us/dotnet/core/extensions/custom-logging-provider
I am struggling with finding a way to register log4net ILog within IServiceCollection services (.NET Core 2.1).
log4net LogManager provides a method that takes a Type as parameter so that it can be used when logging events. Here is an example call:
var log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
However when registering it with services at Startup method, I can use factory resolver, but still the type will be always the same. See the following excerpt:
private void SetServices(IServiceCollection services)
{
services.AddTransient(svc => CreateLog(MethodBase.GetCurrentMethod().DeclaringType)).;
}
protected ILog CreateLog(Type type)
{
return LogManager.GetLogger(type);
}
I was expecting that svc (IServiceProvider) will expose some ways to get to the type being actually resolved but there doesn't seem to be anything.
Also using reflection won't help (IMO, but I could be wrong) because ILog is activated prior to calling the resolved type ctor.
But maybe there is any extension on either MS side or log4net that would help resolving a named logger as explained on the beginning?
This is all to avoid having static members of ILog in any class that uses logging facility and use dependency injection instead.
Thanks, Radek
The way to do it is to implement and then register your own strongly typed Logger class that derives from ILogger.
.Net Core allows from to register generic type interface implementation with no type specified. In this case it would be:
services.Add(ServiceDescriptor.Singleton(typeof(ILogger<>), typeof(MyLogging.Logger<>)));
This allows all classes that require logging to use constructor injection as follows:
class A
{
public A(Ilogger<A> logger) {...}
}
Implementation of ILogger which a wrapper to log4net should be rather simple. Please let me know if you need an example.
Radek
Some background, I built my first .Net Core 2.0 API app that is hosted in a company intranet and used only by internal employees. The app needs to know who the user is on all pages, to work properly, but we don't want to add login/logout/authentication/sessions since the information doesn't need to be secured, it's only to personalize the user's data. I have enabled Windows Authentication successfully and I'm seeing the username (DOMAIN/USERNAME) displayed to the screen when I use the following in a controller:
User.Identity.Name
However, I wanted to get the same username (NTID) in my UserService instead, so that anytime the username is needed, any of the Services can call UserService to get the username.
I have tried all of the following in my UserService, but none of them provide the NTID from IIS:
...
return WindowsIdentity.GetCurrent().Name;
...
return System.Threading.Thread.CurrentPrincipal.ToString();
...
return Environment.UserName;
....
Since this is a REST API, I won't be using Views (I'm aware you can get the username in the View).
Is there an easy approach to get the username outside of the controller? I have found multiple examples online but they are all for < .Net Core 2.0.
In core, HttpContext is injected now, instead of being a thread static. That means the old style of using a static accessor like what you're trying won't work.
To access the HttpContext in something it is not automatically injected into (like a controller), you need to inject IHttpContextAccessor. For example:
public class UserService
{
protected readonly IHttpContextAccessor httpContextAccessor;
public UserService(IHttpContextAccessor httpContextAccessor)
{
this.httpContextAccessor = httpContextAccessor;
}
...
}
Then, as long as you register your service via the ASP.NET Core DI container, an instance will be injected automatically into your service. You can then simply do:
var username = httpContextAccessor.HttpContext.User.Identity.Name;
I'm creating an ASP.NET Web API 2.1 site and as I want to inject dependencies directly into the controllers, I've created my own implementation of IDependencyResolver so that StructureMap will handle that for me.
public class StructureMapDependencyResolver : IDependencyResolver
{
public IDependencyScope BeginScope()
{
return this;
}
public object GetService(Type serviceType)
{
return ObjectFactory.GetInstance(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return ObjectFactory.GetAllInstances(serviceType).Cast<object>();
}
public void Dispose()
{
}
}
I've then told Web API to use this class by adding this line to the Application_Start method in Global.asax
GlobalConfiguration.Configuration.DependencyResolver = new StructureMapDependencyResolver();
That compiled but when I tried to access any of the API methods in a browser I got an error like this
No Default Instance defined for PluginFamily System.Web.Http.Hosting.IHostBufferPolicySelector, System.Web.Http
That one was relatively easy to solve as I added a line to my StructureMap configuration
this.For<IHostBufferPolicySelector>().Use<WebHostBufferPolicySelector>();
However then I got other similar errors for other System.Web.Http classes and while I could resolve some of them I am stuck on how to deal with 3 of them, namely ITraceManager, IExceptionHandler and IContentNegotiator.
The issue is that TraceManager which seems to be the default implementation of ITraceManager is an internal class and so I can't reference it in my StructureMap configuration.
So am I going about this completely the wrong way or is there some other way to inject these internal classes?
I'd like to give you a suggestion and explanation why not to go this way, and how to do it differently (I'd even say better and properly).
The full and complete explanation of the inappropriate IDependencyResolver design could be found here: Dependency Injection and Lifetime Management with ASP.NET Web API by Mark Seemann
Let me cite these essential parts:
The problem with IDependencyResolver
The main problem with IDependencyResolver is that it's essentially a Service Locator. There are many problems with the Service Locator anti-pattern, but most of them I've already described elsewhere on this blog (and in my book). One disadvantage of Service Locator that I haven't yet written so much about is that within each call to GetService there's no context at all. This is a general problem with the Service Locator anti-pattern, not just with IDependencyResolver.
And also:
...dependency graph need to know something about the context. What was the request URL? What was the base address (host name etc.) requested? How can you share dependency instances within a single request? To answer such questions, you must know about the context, and IDependencyResolver doesn't provide this information.
In short, IDependencyResolver isn't the right hook to compose dependency graphs. **Fortunately, the ASP.NET Web API has a better extensibility point for this purpose. **
ServiceActivator
So, the answer in this scenario would be the ServiceActivator. Please take a look at this answer:
WebAPI + APIController with structureMap
An example of the ServiceActivator:
public class ServiceActivator : IHttpControllerActivator
{
public ServiceActivator(HttpConfiguration configuration) {}
public IHttpController Create(HttpRequestMessage request
, HttpControllerDescriptor controllerDescriptor, Type controllerType)
{
var controller = ObjectFactory.GetInstance(controllerType) as IHttpController;
return controller;
}
}
All we can do with StructureMap, is in place. The key features of the Web API framework are still in place... we do not have to hack them. And we are also rather using DI/IoC then Service locator
Just try using UnityHierarchicalDependencyResolver instead of the other one. It worked for me. This is for future reference if somebody would like to use Unity
I have several .asmx web services that I want to upgrade to WebAPI. These web services look somewhat like this:
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService]
public class TheWebService : System.Web.Services.WebService {
[WebMethod(EnableSession = true)]
public string SomeMethod(string SomeInput)
{
MySessionModel TheSession = HttpContext.Current.Session["UserSession"] as MySessionModel;
return SomeClass.SomeMethod(SomeInput, TheSession);
}
}
Basically, I have a single-page application. I'm using Forms Auth to login and redirect users to their "profile" and then, from this page, the app uses web services to communicate with the server. The web services only return raw strings so I don't need serialization at teh web service level. For the moment, the app is hosted in IIS and soon I'll be deploying it into azure.
I've looked around on the web, and several posts suggest that using session state and HttpContext is bad design. Why is using HttpCurrent and session state a bad idea in this case?
There is nothing innately wrong with using ASP.NET Session, as long as you don't use it as a catch-all basket for any old data. Shopping carts, for example, do not belong in Session: they belong in a Shopping Cart persistence component.
Also, and I suspect the reason for the Azure tag on this question, if you are running in a load-balanced environment such as an Azure Cloud Service, you need to use an external session provider such as a SQL Database or a shared cache. Using the in-process session provider (the default) will cause very odd, often unreproducable bugs as users are switched between different servers with different copies of the session.
As for HttpContext.Current, well, for Web API, things like Inversion of Control, Dependency Injection, and simple testability are important. A clean, testable Web API version of that service might look something like this:
public class TheWebService : ApiController {
private readonly IUserSession _userSession;
public TheWebService(IUserSession userSession)
{
_userSession = userSession;
}
public string SomeMethod(string SomeInput)
{
MySessionModel TheSession = _userSession.Get();
return SomeClass.SomeMethod(SomeInput, TheSession);
}
}
public interface IUserSession
{
MySessionModel Get();
}
You could still use HttpContext.Current.Session["UserSession"] in a class like this:
public class CurrentContextUserSession : IUserSession
{
public MySessionModel Get()
{
return HttpContext.Current.Session["UserSession"] as MySessionModel;
}
}
You would then use an IoC container such as Unity or Ninject to set CurrentContextUserSession as the implementation of IUserSession for Web API to use when constructing instances of TheWebService. But when you were writing your tests, you could use a mock or stub implementation of IUserSession that had no dependency on HttpContext.Current.
In your specific example, you are using the Session only inside the WebMethod, which is fine as it is already coupled to ASP.NET but many people tend to use this at other layers of their application which is a really bad design.
Common problems of using HttpContext.Current in those layers are:
the code cannot be easily unit tested in isolation
the code is tightly coupled to an ASP.NET context
This being said, having stateful services that depend on the session is bad design. In the example you have shown, that's an ASMX WebService which is depending on the ASP.NET Session state meaning that the client should be passing cookies around in order to invoke this service. Also stateful services are harder to scale.