ASP.NET 5 / MVC 6, How to use session in class library? - session

With .NET 4.6.1 I wanna use Sessionstate in a class library, something like :
public static void SetUserId()
{
HttpContext.Current.Session["userId"] = 1;
}
but when I call this method it throws an exception "An unhandled exception occurred while processing the request." > "NullReferenceException: Object reference not set to an instance of an object."
I have a reference to system.Web in my class library. In .NET 4 I can do this safe. But it is a problem in .NET 4.6.1.
How can I solve this?
Thanks

This is null by default, the concept driving ASP.NET Core 1.0 is pluggable middleware. You need to explicitly opt-in for session.
You need to ensure that both the Microsoft.Extensions.Caching.Memory and Microsoft.AspNet.Session dependencies exists in the project.json. Then in your
Startup.cs add the following:
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
services.AddCaching();
services.AddSession(options => {
options.IdleTimeout = TimeSpan.FromMinutes(30);
options.CookieName = ".MyApplication";
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseSession();
// Removed for brevity...
}
Detailed article here. That should be all you need to do.
Update
Avoid attempting to use HttpContext.Current outside of the web application. This is intended only within the context of the HTTP request / response pipeline. It is preferred to utilize abstractions to achieve the desired interactions you're looking for.
I would need you to share more source code in order to provide an explicit example.

Related

FluentValidations in Test project redirects to the main API project because of WebApplicationFactory

I was using WebApplicationFactory for integration tests, but then I wanted to use DI for my test classes for my services and repos and Xunit was not a big fan of interfaces and ctors, so I wanted to put all my services and dependencies in WebApplicationFactory which I think is the appropriate way but the thing is my main API project is a fully functioning API with auth (such as MSAL and branches, users that require internet connection). So, every time I call a validator I get 401
public class SqliteTests : IClassFixture<ApiWebAppFactory>
{
private readonly IValidator<Contact> _validator;
public SqliteTests(ApiWebAppFactory factory)
{
var scope = factory.Services.GetRequiredService<IServiceScopeFactory>().CreateScope();
//401 unauthorized here
_validator = scope.ServiceProvider.GetRequiredService<IValidator<Contact>>();
}
[Fact]
public async void MyTest()
{
//...
}
}
I usually fix this kind of problem by returning new objects from the IServiceProvider's ctor
like this:
public class ApiWebAppFactory :
WebApplicationFactory<Actual.API.Mappings.MappingProfiles>
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
//...
services.AddScoped<IRepository<Contact>, Repository<Contact>>
(x =>
{
return new Repository<Contact>(x.GetRequiredService<SqliteMockDbContext>());
});
//...
But I couldn't find a way to do the same thing with the FluentValidation; validation and ValidatorFactory(some of our services use IValidatorFactory).
They always seem to call to the main API project's Program.cs and its all dependencies which ends up in 401 Unauthorized.
This code might look ugly but I also have the same issue with my IService which expects an IValidatorFactory;
services.AddScoped<IService<Contact, IRepository<Contact>,
BaseResponse<Contact>, BaseResponseRange<IEnumerable<BaseResponse<Contact>>,
Contact>>, Service<Contact, IRepository<Contact>, BaseResponse<Contact>,
BaseResponseRange<IEnumerable<BaseResponse<Contact>>, Contact>>>(
x =>
{
var repo = x.GetRequiredService<IRepository<Contact>>();
var uow = x.GetRequiredService<IUnitOfWork>();
return new Service<Contact, IRepository<Contact>, BaseResponse<Contact>,
BaseResponseRange<IEnumerable<BaseResponse<Contact>>, Contact>>(
repo,uow, //this = new ServiceProviderValidatorFactory(x)
);
}

How to unit test an action filter attribute for web api in asp.net core?

I have written an action filter for a web api. If a method in the api controller throws an unhandled exception, then the filter creates an internal error 500 response.
I need to know how to test the filter?
I have researched extensively but could not create a suitable test. I tried context mocking, a service locator implementation and even an integration test using a test server.
The web api controller looks like this:
namespace Plod.Api.ApiControllers
{
[TypeFilter(typeof(UnhandledErrorFilterAttribute))]
[Route("api/[controller]")]
public class GamesController : BaseApiController
{
public GamesController(IGameService repository,
ILogger<GamesController> logger,
IGameFactory gameFactory
) : base(
repository,
logger,
gameFactory
)
{ }
// ..... controller methods are here
}
}
The complete controller is found here.
The filter is this:
namespace Plod.Api.Filters
{
public class UnhandledErrorFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext.Exception != null)
{
filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
filterContext.ExceptionHandled = true;
}
}
}
}
I even welcome changes to the filter implementation as a possible work around. Any help or ideas would be much appreciated. Thanks.
You probably can't. However, what you can do is spin up a TestServer and then hit it with a HttpClient. This really is an integration test and not a unit test. However, it's the good kind of integration test because it can be run safely in pipelines.
This document explains how to do this:
https://learn.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-3.1
The issue you are going to face is that you will need to mock the underlying services inside your app. If you don't do that, your whole server will spin up and attempt to hit the database etc. Here is an example. This is using Moq. Incidentally I am sharing the ConfigureServices method with unit tests so they use the same object mesh of mocked services. You can still use the full functionality of Moq or NSubstitute to test the back-end (or even front -end).
I can hit my attributes in the test with breakpoint.
private void ConfigureServices(IServiceCollection services)
{
var hostBuilder = new WebHostBuilder();
hostBuilder.UseStartup<TestStartup>();
hostBuilder.ConfigureServices(services =>
{
ConfigureServices(services);
});
_testServer = new TestServer(hostBuilder);
_httpClient = _testServer.CreateClient();
}
private void ConfigureServices(IServiceCollection services)
{
services.AddSingleton(_storageManagerFactory.Object);
services.AddSingleton(_blobReferenceManagerMock.Object);
services.AddSingleton(_ipActivitiesLoggerMocker.Object);
services.AddSingleton(_loggerFactoryMock.Object);
services.AddSingleton(_hashingService);
services.AddSingleton(_settingsServiceMock.Object);
services.AddSingleton(_ipActivitiesManager.Object);
services.AddSingleton(_restClientMock.Object);
_serviceProvider = services.BuildServiceProvider();
}
public class TestStartup
{
public void Configure(
IApplicationBuilder app,
ISettingsService settingsService)
{
app.Configure(settingsService.GetSettings());
}
public IServiceProvider ConfigureServices(IServiceCollection services)
{
var mvc = services.AddMvc(option => option.EnableEndpointRouting = false);
mvc.AddApplicationPart(typeof(BlobController).Assembly);
services.AddSingleton(new Mock<IHttpContextAccessor>().Object);
return services.BuildServiceProvider();
}
}

MVC5 dependency injection issue

I have created an application using MVC5 with the onion architecture approach. The solution contains 3 projects (core, infrastructure, and UI). The UI contains both Web API controllers and MVC controllers. The issue I’m running into is dependency injection. I have installed Unity.MVC5 & Unity.WebApi. My UnityConfig.cs under App_Start Looks like this:
public static void RegisterComponents()
{
var container = new UnityContainer();
container.RegisterType<IPricingService, PricingService>();
GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);
}
My global.asax looks like this:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
System.Web.Http.GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
UnityConfig.RegisterComponents();
}
To test out my controller, I defined my home controller like this:
private readonly IPricingService _pricingService;
public HomeController(IPricingService PricingService)
{
this._pricingService = PricingService;
}
When running home page I get
No parameterless constructor defined for this object.
Now, moving to another test scenario, I created a web api controller and looks like this:
private readonly IPricingService _pricingService;
public TestApiController(IPricingService PricingService)
{
this._pricingService = PricingService;
}
Testing the web api generates this error:
An error occurred when trying to create a controller of type 'TextApiController'. Make sure that the controller has a parameterless public constructor.","exceptionType":"System.InvalidOperationException"
Not sure what I'm missing. Please advise.
You are supposed to inject the Unity.WebApi.DependencyResolver into the WebApi configuration not in GlobalConfiguration.Configuration.DependencyResolver.
public static void Register(HttpConfiguration config)
{
var container = new UnityContainer();
container.RegisterType<IProductRepository, ProductRepository>(new HierarchicalLifetimeManager());
config.DependencyResolver = new UnityResolver(container);
// Other Web API configuration not shown.
}
You also need to implement a child container in the BeginScope method as shown in this MSDN article.

How to selectively enable JSONP on WebAPI actions?

I'm using ASP.NET Web API v2.0 to build an web api.
I need to make some of the controllers/actions available in CORS/JSONP, so I chose to use WebApiContrib.Formatting.Jsonp.
Because I'm not use Web API v2.1 yet, I can only use WebApiContrib v0.9.7.0.
If I add the JSONP formatter in Global.ascx.cs, it'll open all my controllers and actions for CORS/JSONP, so I wrote the Action Filter below to add and remove the formatter at specific times.
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class EnableCorsAttribute : System.Web.Http.Filters.ActionFilterAttribute
{
public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
{
var config = System.Web.Http.GlobalConfiguration.Configuration;
config.Formatters.Insert(0, new WebApiContrib.Formatting.Jsonp.JsonpMediaTypeFormatter(config.Formatters.JsonFormatter));
}
public override void OnActionExecuted(System.Web.Http.Filters.HttpActionExecutedContext actionExecutedContext)
{
var config = System.Web.Http.GlobalConfiguration.Configuration;
config.Formatters.RemoveAt(0);
}
}
Now, my question is that will that code be thread safe if multiple requests are coming in?

Server-side schema validation with JAX-WS

I have JAX-WS container-less service (published via Endpoint.publish() right from main() method). I want my service to validate input messages. I have tried following annotation: #SchemaValidation(handler=MyErrorHandler.class) and implemented an appropriate class. When I start the service, I get the following:
Exception in thread "main" javax.xml.ws.WebServiceException:
Annotation #com.sun.xml.internal.ws.developer.SchemaValidation(outbound=true,
inbound=true, handler=class mypackage.MyErrorHandler) is not recognizable,
atleast one constructor of class
com.sun.xml.internal.ws.developer.SchemaValidationFeature
should be marked with #FeatureConstructor
I have found few solutions on the internet, all of them imply the use of WebLogic container. I can't use container in my case, I need embedded service. Can I still use schema validation?
The #SchemaValidation annotation is not defined in the JAX-WS spec, but validation is left open. This means you need something more than only the classes in the jdk.
As long as you are able to add some jars to your classpath, you can set this up pretty easily using metro (which is also included in WebLogic. This is why you find solutions that use WebLogic as container.). To be more precise, you need to add two jars to your classpath. I'd suggest to
download the most recent metro release.
Unzip it somewhere.
Add the jaxb-api.jar and jaxws-api.jar to your classpath. You can do this for example by putting them into the JAVA_HOME/lib/endorsed or by manually adding them to your project. This largely depends on the IDE or whatever you are using.
Once you have done this, your MyErrorHandler should work even if it is deployed via Endpoint.publish(). At least I have this setup locally and it compiles and works.
If you are not able to modify your classpath and need validation, you will have to validate the request manually using JAXB.
Old question, but I solved the problem using the correct package and minimal configuration, as well using only provided services from WebLogic. I was hitting the same problem as you.
Just make sure you use correct java type as I described here.
As I am planning to expand to a tracking mechanism I also implemented the custom error handler.
Web Service with custom validation handler
import com.sun.xml.ws.developer.SchemaValidation;
#Stateless
#WebService(portName="ValidatedService")
#SchemaValidation(handler=MyValidator.class)
public class ValidatedService {
public ValidatedResponse operation(#WebParam(name = "ValidatedRequest") ValidatedRequest request) {
/* do business logic */
return response;
}
}
Custom Handler to log and store error in database
public class MyValidator extends ValidationErrorHandler{
private static java.util.logging.Logger log = LoggingHelper.getServerLogger();
#Override
public void warning(SAXParseException exception) throws SAXException {
handleException(exception);
}
#Override
public void error(SAXParseException exception) throws SAXException {
handleException(exception);
}
#Override
public void fatalError(SAXParseException exception) throws SAXException {
handleException(exception);
}
private void handleException(SAXParseException e) throws SAXException {
log.log(Level.SEVERE, "Validation error", e);
// Record in database for tracking etc
throw e;
}
}

Resources