Accessing Session via ICacheClient during unit testing ServiceStack Service - c#

We've got a ServiceStack 3.9.x service that we're trying to unit test end-to-end (via an in-process service host and accessing it via C# native clients), and we're running into a snag where it seems that the session is not accessible via the means we typically use to access it when running this way.
We typically access the current session (using servicestack's built-in system and custom AuthSession and providers, which all works fine running in IIS against an AppHost derived from AppHostBase) using this:
EndpointHost.AppHost.TryResolve<ICacheClient>().SessionAs<SsoUserSession>();
However, when trying to access this in unit testing (against an AppHost derived from AppHostHttpListenerBase), we get an exception thrown trying to get at the session: "Only ASP.NET Requests accessible via Singletons are supported" which appears to be a hard-coded error in the SessionFeature.
So the question is this: can one access sessions via the cache provider when unit testing via a service host derived from AppHostHttpListenerBase? And if so, how?

I've run into this before too.
The way I handle it is create create something like an extension method to get the session from the cache client that just calls the base, but before calling the base..check the IoC container for the session first. If it's there, just use that instead, and I just inject the session I want to use when testing.
This is used somewhere in servicestack but I can't seem to find the method that does it...anyway an extension method could look something like this
public static MyTypedSession GetMyTypedSession(this ICacheClient cache)
{
var typedSession = ServiceStackHost.Instance.Container.TryResolve<MyTypedSession>();
if (typedSession != default(MyTypedSession))
return typedSession;
return cache.SessionAs<MyTypedSession>();
}
Then instead of calling SessionAs in your code to get the typed session, you would just call GetMyTypedSession, and it would work fine for testing, so long as you Register your fake MyTypedSession
Here's some c# psuedo test method
public void SomeTestMethod()
{
var session = new MyTypedSession { IsAuthenticated = true; };
//get your container and register the session
container.Register(session);
var someValue = TestCodeThatUsesASession();
Assert(someValue);
}
I'm unsure what kinda delay looking in the IoC container everytime you need a session is though.
Sorta strange to add that code just for testing but oh well, works for me and save me time :).

Related

DI Singleton Service Instantiates Twice

I register a service as Singleton in the program.cs file like this.
builder.Services.AddSingleton<ITest, Test>();
and if I request an instance of it in program.cs
var testService = builder.Services.BuildServiceProvider()
.GetRequiredService<ITest>();
It creates a new object which is the first object, but when I request it through constructor injection in some other service it creates a new object again. Shouldn't it return the first object that it created while startup in Program.cs?
Note : This behavior is only if I request service in the program.cs other than that it returns the same object, even if I request it using IServiceProvider.GetRequiredService();
i have tested the same scenario in dot net 5 web api as well in which i register the service in ConfigureServices method of Startu.cs file
services.AddSingleton<ITest, Test>();
and request the service in Configure method like this
var test = app.ApplicationServices.GetRequiredService<ITest>();
and when i request it in constructor in some other service it will return the same object.
Why?
In your starup file, you don't have a service provider yet. You only have the Services property that allows you to define your services.
Since you want to instantiate one, you call builder.Services.BuildServiceProvider() which builds a service provider for you, that you then use to get a service. Inside that service provider, your service lives as singleton.
Then, you proceed in your application and the framework, being happy that you defined your services, then builds it's own service provider. Which you can access via app.ApplicationServices. That one, too, has a single instance of your class, since it's a singleton.
And from now on, since all your services and controllers use the service provider created by the framework, not the one you created manually in startup, all of them will get the same instance.

Why does the DatabaseInitializer get called twice?

I’ve inherited an MVC that currently does some setup work with the ApplicationStart method so that when the application comes back to life with an IIS Application pool this setup has already been carried out.
As pseudo-code:
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
// Build Api autofac container
// Build MVC autofac container
// Resolve serviceOne from the MVC container
var serviceOne = (IServiceOne)DependencyResolver.Current.GetService(typeof(IServiceOne));
// Make setup call - includes external http calls and DbContext checking
serviceOne.syncToExternal();
// Resolve serviceTwo again from the MVC container
var serviceTwo = (IServiceTwo)DependencyResolver.Current.GetService(typeof(IServiceTwo));
// Make setup call - publishes application information to internal message queues so that we know it's running
serviceTwo.syncToInternalSystems();
}
}
In the ApplicationStart I run through the normal process of setting up Autofac containers; one for the MVC and one for the WebApi. In here the respective MVC or Api controllers, service classes and my DbContext are registered.
The setup work in the ApplicationStart needs a service and a DbContext which I resolve from the MvcContainer, as the WebApi one is not accessible at this point.
ServiceOne retrieves data from an external url and using this to seed / check the current contents of the database.
ServiceTwo reads back some of this data and publishes it to internal message queues within the company.
Once the Application_Start() has finished and the Home page has loaded: if I make a request which routes through the MVC then the DbCobntext's registered databaseInitialzer does not get called as it was run during the Application_Start, but if I make an /api request the databaseInitializer does get called.
I suspect that running the setup in ApplicationStart method is preventing a flag being set in the System.Data.Entity.Database which managed the Connection; hence when the DbContext is resolved from the Api Container it thinks the database hasn’t been initialised...?
Any help would be much appreciated.
My fallback will be to shift all of the setup into a seed method which runs when the databaseInitialiser/Migration is called; but it would be useful to know why the original version of the code was failing to execute as expected.
the ApplicationStart run every time the ApplicationPool starts, no matter what. You have to use another mechanism to populate your DB. Like Migrations.

Integration testing ASP.NET Web API 2 using HttpServer/HttpClient; no HttpContext

I'm looking to integration test a web service built on ASP.NET Web API 2. Many things such as cookies, getting the current principal, etc. are done through HttpContext.Current.
I found the following resource on integration testing ASP.NET:
http://amy.palamounta.in/blog/2013/08/04/integration-testing-for-asp-dot-net-web-api/
This works great. It spins up an in-memory host and combined with the automated schema generation of Entity Framework 6, setup and teardown are easy.
The problem comes in when things try and use HttpContext.Current to, as aforementioned, get cookies/etc. It seems that when hosting in-memory using HttpServer, HttpContext.Current is always null. This does make a little sense given there's no real request, but is a pain - it means the integration tests can't cover anything requiring anything from this property.
What can I do here? It looks like very little of the data I'm using is present anywhere but HttpContext.Current, so am I just going to have to spin up full external instances on IIS?
In order to test your api using self host you have to avoid calling HttpContext.Current from a web api context. You can wrap it in something you can mock, like so:
public static class CurrentHttpContext
{
public static Func<HttpContextBase> Instance = () => new HttpContextWrapper(HttpContext.Current);
}
Then when you are creating your test server you could set the CurrentHttpContext to some fake HttpContextBase. For example using FakeItEasy (http://fakeiteasy.github.io/):
var context = A.Fake<HttpContextBase>();
CurrentHttpContext.Instance = () => context;
And then use this anywhere you need to access HttpContext:
var context = CurrentHttpContext.Instance();
// do what you need to do to httpcontext now like setting principal, cookies etc

How to create a WCF Service that has an always running component?

Half a day of googling suggests, that it's a bit niche topic, and my question is quite specific. I'm using: VS2013, .NET 4.5, IIS 8.5
I have a ASP.NET website that needs to query a data source. Opening the data source is costly, but I can keep it open indefinitely.
My idea was: create a Command Line application or a Windows Service that will open the data source and then expose the querable objects to the ASP.NET website.
I don't like the idea of having this unmanaged (CommandLine) or managed apart from website (WinService) application that I have to deploy completely separately.
I've read that it is possible to create an always running WCF service hosted in IIS. I would like it to keep a list of object instances that would be returned as a result of a WCF call. Is that at all possible? If yes, how?
I've tried setting the WCF service AppPool to AlwaysRunning, enabling autostart on service application and I can access the service, but a simple test shows, that the service object is created every time anew:
public class MyService : IMyService{
{
private int _counter;
public int Test(){ return _counter++; }
}
My website creates a MyServiceClient from service reference and calls test - it returns 0 every time.
I've also found, that if I create any class in my WCF service application, I cannot access it from inside MyService methods. I can access though classes referenced from other projects. Why is that?
I think you're looking for a singleton service. By default the ServiceBehaviorAttribute.InstanceContextMode is set to PerSession. Instead set it to Single. Every client will then connect to the same instance of the service.
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
public class MyService : IMyService{
{
private int _counter;
public int Test(){ return _counter++; }
}
Personally, I prefer the singleton approach over static as discussed in here

c# client calling java axis2 web service, object "resets"

I am very new to web service stuff so please be kind.
I have written a simple POJO class, and deployed it on an axis2 server:
public class Database {
private Project project;
public void login(){
project = new Project();
project.setDescription("Hello there");
project.setName("To me");
}
public Project getProject(){
return project;
}
}
I call the service from a c# client:
localhost.Database db = new WindowsFormsApplication1.localhost.Database();
db.login();
localhost.getProjectResponse pr = new WindowsFormsApplication1.localhost.getProjectResponse();
pr = db.getProject();
When I debug the response is null.
At the java end, when I call getProject, the project object is null.
What's happening?
How do I preserve the state of project between service calls?
For most toolkits, web services are stateless by default. I think axis is no different.
If you want to maintain state between calls then you will need to enable sessions. An example on how to maintain sessions in axis can be found at:
http://kickjava.com/src/test/session/TestSimpleSession.java.htm
On the .NET side you will need to assign a CookieContainer to your request to store the session identifier. See HOW TO: Use CookieContainer to Maintain a State in Web Services for more information.
I think your code would look something like this:
localhost.Database db = new WindowsFormsApplication1.localhost.Database();
// Assign the CookieContainer to the proxy class.
db.CookieContainer = new System.Net.CookieContainer();
db.login();
localhost.getProjectResponse pr = new WindowsFormsApplication1.localhost.getProjectResponse();
pr.CookieContainer = db.CookieContainer;
pr = db.getProject();
I think that should let you do what you want -- but I wouldn't recommend it.
Designing service interfaces is a bit different than designing object oriented interfaces. Service interfaces typically eschew the use of state and instead require the consumer to provide all of the relevant information in the request.
From Service-Oriented Architecture:
Services should be independent,
self-contained requests, which do not
require information or state from one
request to another when implemented.
I would definitely recommend reading that article and perhaps revisiting your design.
I'm not sure why #shivaspk left a comment instead of writing an answer, it is quite correct: web service calls (not just axis calls) are meant to be stateless, so although the project object gets created by
db.login();
when you call
db.getProject();
It is being called on a different instance of your Database class that was created by Axis to service the second call.
There is no really good answer to your question, except for you to rethink what you are trying to do. If you need some kind of authentication (via login), then that authentication needs to be part of every web service call.

Categories