isnt there a way, or am i doing something wrong, to have persistant members in a c# grpc service?
Heres what i mean:
my Service:
public class AcquisitionService : Acquisition.AcquisitionBase {
private string _test;
public override Task<Reply> Test1(Request request, ServerCallContext context) {
_test = "5";
_logger.LogInformation("test: " + _test);
return Task.FromResult(new Reply());
}
public override Task<Reply> Test2(Request request, ServerCallContext context) {
_logger.LogInformation("test: " + _test);
return Task.FromResult(new Reply());
}
}
when i call these methods like:
using var channel = GrpcChannel.ForAddress("https://localhost:7110");
var acqClient = new Acquisition.AcquisitionClient(channel);
acqClient.Test1(new Request {});
acqClient.Test2(new Request {});
from service my output in logger is:
test: 5
test:
why is the content of _test disposed?
Im new to grpc.
Thanks
i tried to add properties but it did not helped.
A new instance of AcquisitionService is instantiated for each call.
This means that every instance field is "brand new" for each new call.
You should use a persistence layer like a database or file or something like that to persist the value of your data across calls.
Another way is to make the _test field static, then the value will be shared for each instance. Make sure you understand the implications of a shared static field (concurrency and so on).
I think the best way is to make the service a singleton in Program.cs:
builder.Services.AddSingleton<AcquisitionService>();
its mentioned here:
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-6.0#service-lifetimes
Related
I have an application that currently works as designed, but I am trying to setup integration testing with xUnit before I expand upon it. At the moment the test will only use the original service when performing the test and I don't see why.
This the is the test:
using IStoreRepository = Repositories.V3.Interfaces.IStoreRepository;
public class StoreTests : IClassFixture<WebApplicationFactory<Startup>> {
private readonly ITestOutputHelper _output;
private readonly WebApplicationFactory<Startup> _factory;
private readonly string _url;
public StoreTests(ITestOutputHelper output, WebApplicationFactory<Startup> factory) {
_output = output;
_factory = factory;
_url = "/api/store";
}
[Theory]
[InlineData("GET", "FAKE123")]
public async Task StoreByCode(string method, string code = null) {
// var client = _factory.CreateClient();
var client = _factory.WithWebHostBuilder(builder => {
builder.ConfigureTestServices(services => {
services.AddScoped<IStoreRepository, StoreRepositoryTest>();
});
}).CreateClient();
var request = new HttpRequestMessage(new HttpMethod(method), $"{_url}/{code}");
string readAsStringAsync;
_output.WriteLine($"Request Uri: {request.RequestUri}");
using (var response = await client.SendAsync(request)) {
response.EnsureSuccessStatusCode();
readAsStringAsync = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode) {
_output.WriteLine($"Not successful ({response.StatusCode}): {readAsStringAsync}");
}
}
var stores = JsonConvert.DeserializeObject<List<Store>>(readAsStringAsync);
Assert.True(stores.Any());
}
}
However when I conduct the test the break point in the real Repository, StoreRepository that is registered in Startup.cs is the one that is hit, not the break point in StoreRepositoryTest. I setup my factory to override the dependency, but it's ignoring it. What can I do to correct this.
For reference, I have been using this source: https://learn.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-2.2
Update
Not sure if this question should be deleted or not but it ended up being a really silly mistake. I updated the code above to include a using alias. It turned out I was registering and overriding the V1 interface instead of V3. When I implemented the Mock class I didn't realize I was implementing the old service. So the good news is the above code is a working example of how to mock using Microsoft's documentation.
I have seen this before. You probably created an interface in a different namespace.
Typically, this happens when you have a version 1 interface for a web service, and then you decide to add new functionality. You then create a version 2 interface with exactly the same name.
Put a break point on services.AddScoped<IStoreRepository, StoreRepositoryTest>() and debug that. Inspect the results and scroll to the bottom where your services are being added; You’ll get a clear view of what’s being added.
1) You can try using CustomWebApplicationFactory class and in ConfigureWebHost(IWebHostBuilder builder) method, add builder.ConfigureServices(//define dependencies).
Refer msdn link
2) Alternatively, you can define your own TestStartup class inheriting from Startup class and use it.
Does any one know if it is possible to host multiple instances of WebApplicationFactory<TStartop>() in the same unit test?
I have tried and can't seem to get anywhere with this one issue.
i.e
_client = WebHost<Startup>.GetFactory().CreateClient();
var baseUri = PathString.FromUriComponent(_client.BaseAddress);
_url = baseUri.Value;
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
"Bearer", "Y2E890F4-E9AE-468D-8294-6164C59B099Y");
WebHost is just a helper class that allows me to build factory and then a client easily in one line.
Under the covers all it does is this:
new WebApplicationFactory<TStartup>() but a few other things too.
It would be nice if i could stand up another instace of a different web server to test server to server functionality.
Does anyone know if this is possible or not?
Contrary to what the accepted answer states, it is actually pretty easy to test server to server functionality using two WebApplicationFactory instances:
public class OrderAPIFactory : WebApplicationFactory<Order>
{
public OrderAPIFactory() { ... }
protected override void ConfigureWebHost(IWebHostBuilder builder) { ... }
}
public class BasketAPIFactory : WebApplicationFactory<BasketStartup>
{
public BasketAPIFactory() { ... }
protected override void ConfigureWebHost(IWebHostBuilder builder) { ... }
}
Then you can instantiate the custom factories as follows:
[Fact]
public async Task TestName()
{
var orderFactory = new OrderAPIFactory();
var basketFactory = new BasketAPIFactory();
var orderHttpClient = orderFactory.CreateClient();
var basketHttpClient = basketFactory.CreateClient();
// you can hit eg an endpoint on either side that triggers server-to-server communication
var orderResponse = await orderHttpClient.GetAsync("api/orders");
var basketResponse = await basketHttpClient.GetAsync("api/basket");
}
I also disagree with the accepted answer about it necessarily being bad design: it has its use-cases. My company has a microservices infrastructure which relies on data duplication across microservices and uses an async messaging queue with integration events to ensure data consistency. Needless to say that messaging functionality plays a central role and needs to be tested properly. A test setup as described here is pretty useful in this situation. For example it allows us to thoroughly test how messages are being dealt with by a service that was down at the moment those messages were published:
[Fact]
public async Task DataConsistencyEvents_DependentServiceIsDown_SynchronisesDataWhenUp()
{
var orderFactory = new OrderAPIFactory();
var orderHttpClient = orderFactory.CreateClient();
// a new order is created which leads to a data consistency event being published,
// which is to be consumed by the BasketAPI service
var order = new Order { ... };
await orderHttpClient.PostAsync("api/orders", order);
// we only instantiate the BasketAPI service after the creation of the order
// to mimic downtime. If all goes well, it will still receive the
// message that was delivered to its queue and data consistency is preserved
var basketFactory = new BasketAPIFactory();
var basketHttpClient = orderFactory.CreateClient();
// get the basket with all ordered items included from BasketAPI
var basketResponse = await basketHttpClient.GetAsync("api/baskets?include=orders");
// check if the new order is contained in the payload of BasketAPI
AssertContainsNewOrder(basketResponse, order);
}
It is possible to host multiple communicating instances of WebApplicationFactory in single integration test.
Let's say we have master service named WebApplication, which depends on utility service named WebService using named HttpClient with name "WebService".
Here is example of integration test:
[Fact]
public async Task GetWeatherForecast_ShouldReturnSuccessResult()
{
// Create application factories for master and utility services and corresponding HTTP clients
var webApplicationFactory = new CustomWebApplicationFactory();
var webApplicationClient = webApplicationFactory.CreateClient();
var webServiceFactory = new WebApplicationFactory<Startup>();
var webServiceClient = webServiceFactory.CreateClient();
// Mock dependency on utility service by replacing named HTTP client
webApplicationFactory.AddHttpClient(clientName: "WebService", webServiceClient);
// Perform test request
var response = await webApplicationClient.GetAsync("weatherForecast");
// Assert the result
response.EnsureSuccessStatusCode();
var forecast = await response.Content.ReadAsAsync<IEnumerable<WeatherForecast>>();
Assert.Equal(10, forecast.Count());
}
This code requires CustomWebApplicationFactory class to be implemented:
// Extends WebApplicationFactory allowing to replace named HTTP clients
internal sealed class CustomWebApplicationFactory
: WebApplicationFactory<WebApplication.Startup>
{
// Contains replaced named HTTP clients
private ConcurrentDictionary<string, HttpClient> HttpClients { get; } =
new ConcurrentDictionary<string, HttpClient>();
// Add replaced named HTTP client
public void AddHttpClient(string clientName, HttpClient client)
{
if (!HttpClients.TryAdd(clientName, client))
{
throw new InvalidOperationException(
$"HttpClient with name {clientName} is already added");
}
}
// Replaces implementation of standard IHttpClientFactory interface with
// custom one providing replaced HTTP clients from HttpClients dictionary
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
base.ConfigureWebHost(builder);
builder.ConfigureServices(services =>
services.AddSingleton<IHttpClientFactory>(
new CustomHttpClientFactory(HttpClients)));
}
}
And finally, CustomHttpClientFactory class is required:
// Implements IHttpClientFactory by providing named HTTP clients
// directly from specified dictionary
internal class CustomHttpClientFactory : IHttpClientFactory
{
// Takes dictionary storing named HTTP clients in constructor
public CustomHttpClientFactory(
IReadOnlyDictionary<string, HttpClient> httpClients)
{
HttpClients = httpClients;
}
private IReadOnlyDictionary<string, HttpClient> HttpClients { get; }
// Provides named HTTP client from dictionary
public HttpClient CreateClient(string name) =>
HttpClients.GetValueOrDefault(name)
?? throw new InvalidOperationException(
$"HTTP client is not found for client with name {name}");
}
The complete code of example you may find here: https://github.com/GennadyGS/AspNetCoreIntegrationTesting
The pros of such approach are:
ability to test interactions between the services;
no need to mock internals of services so that you can consider them as black boxes;
tests are stable to any refactorings including changes in communication protocol;
tests are fast, self-contained, do not require any prerequisites and give predictable results.
The main cons of such approach is possible conflicting dependencies of participating services (e.g. different major versions of EFCore) in real world scenarios due to the fact that all services using in test are running in single process.
There are several mitigations of such problem. One of them is to apply modular approach to services' implementations and load modules in runtime according to configuration file. This may allow to replace configuration file in tests, exclude several modules from loading and replace missing services with simpler mocks. The example of applying such approach you may find in branch "Modular" of the example repository above.
I was based on Gennadii Saltyshchak's solution to create this, which is exaclty what I was looking for: Two servers communicating with one another via a fallback mechanism.
In this example one server runs on port 80 and the other on 82 and there is an api endpoint called fallback that calls the hello endpoint on the fallback server.
Full solution can be found here: https://github.com/diogonborges/integration-test-communicating-servers
public class Tests
{
private HttpClient _port80Client;
private HttpClient _port82Client;
[SetUp]
public void Setup()
{
// Create application factories for master and utility services and corresponding HTTP clients
var port80Factory = new CustomWebApplicationFactory(80, 82);
_port80Client = port80Factory.CreateClient();
port80Factory.Server.Features.Set<IServerAddressesFeature>(new ServerAddressesFeature {Addresses = {"http://localhost:80"}});
var port82Factory = new CustomWebApplicationFactory(82, 80);
_port82Client = port82Factory.CreateClient();
port82Factory.Server.Features.Set<IServerAddressesFeature>(new ServerAddressesFeature {Addresses = {"http://localhost:82"}});
// Mock dependency on utility service by replacing named HTTP client
port80Factory.AddHttpClient(Constants.Fallback, _port82Client);
port82Factory.AddHttpClient(Constants.Fallback, _port80Client);
}
[Test]
public async Task Port80_says_hello()
{
var response = await _port80Client.GetAsync("hello");
var content = await response.Content.ReadAsStringAsync();
Assert.AreEqual("hello from http://localhost:80", content);
}
[Test]
public async Task Port80_falls_back_to_82()
{
var response = await _port80Client.GetAsync("hello/fallback");
var content = await response.Content.ReadAsStringAsync();
Assert.AreEqual("hello from http://localhost:82", content);
}
[Test]
public async Task Port82_says_hello()
{
var response = await _port82Client.GetAsync("hello");
var content = await response.Content.ReadAsStringAsync();
Assert.AreEqual("hello from http://localhost:82", content);
}
[Test]
public async Task Port82_falls_back_to_80()
{
var response = await _port82Client.GetAsync("hello/fallback");
var content = await response.Content.ReadAsStringAsync();
Assert.AreEqual("hello from http://localhost:80", content);
}
}
No. It's not possible. WebApplicationFactory leans on xUnit's IClassFixture, which has to be applied at the class level, meaning you only get one bite at the apple. The WebApplicationFactory itself is capable of being customized per test, which fulfills most use cases where you're need a "different" one, but it doesn't help you wanting two totally separate active test servers at the same time.
However, that said, what you're wanting is a bad test design in the first place. The whole point of testing is to eliminate variables so you can actually ensure the piece of the SUT is actually working. Even in an integration testing environment, you're still just looking at one particular interaction between pieces of your application. Have two test servers, feeding off each other, effectively multiplies the variables giving you no assurance that either side is working correctly.
I am making a DLL to consume a REST API in aspnetcore.
Ideally, I would like it to be accessed this way:
API api = new API(clientInfo);
api.Module.Entity.Action(params);
But I am struggling to make that a reality. I can't make anything static because more than 1 session might be instanced at the same time. I can't pass the session around except by reference otherwise session state(cookies etc.) might change in the copy. Is there a design pattern I should be using?
public class API
{
private Session _session;
public API(ClientInfo clientInfo)
{
_session = new Session(clientInfo);
}
}
The session serves as middleware for the client, stores login data in case the client needs to repeat login, handles some errors/retries and exposes client methods.
public class Session
{
private Client _client;
private string _path;
public Session(ClientInfo clientInfo)
{
_client= new Client(clientInfo);
_path = clientInfo.Path;
}
public HttpResponseMessage Get(string name, string arguments = "")
{
return _client.Get(_path, name, arguments);
}
...
}
The client actually performs the calls.
public class Client
{
public HttpResponseMessage Get(string path, string endpointName, string arguments)
{
return GetClient().GetAsync(path + endpointName + arguments).Result;
}
private HttpClient GetClient(){...}
...
}
Personally, I just build a simple client for my APIs, with methods corresponding to the endpoints the API has:
public class FooClient
{
private readonly HttpClient _httpClient;
public FooClient(HttpClient httpClient)
{
_httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
}
public async Task<GetFooResult> Get(int id)
{
...
}
// etc
}
The HttpClient dependency is provided by registering a typed client in Startup.cs:
services.AddHttpClient<FooClient>(c =>
{
// configure client
});
And I add an IServiceCollection extension to encapsulate this and any other setup logic:
public static class IServiceCollectionExtensions
{
public static IServiceCollection AddFooClient(this IServiceCollection services, string uri)
{
...
}
}
Then, in my Startup, I can simply do something like:
services.AddFooClient(Configuration.GetValue<string>("FooUri"));
This is extremely helpful for setting up automatic error handling, retry policies, etc. via Polly, as you can then set up all that configuration just once in the extension.
Now, getting to your issue of persisting things like auth tokens, you have a few possibilities. I tend to prefer persisting auth tokens as claims, in which case you can simply retrieve the claim and pass it into methods on your client that need it:
var foo = await _fooClient.Get(fooId, User.FindFirstValue("FooAuthToken"));
If you handle things that way, you can bind your client in any scope, including singleton.
An alternative approach would be to actually persist the auth token in your client, but this has to be done with care. You should definitely avoid using singleton scope, unless you're employing something like a ConcurrentDictionary and even then, ensuring that the right token is always used could be a bit gnarly.
Assuming you're using a request scope, you can store the token directly as an ivar or something, but you'd still need to persist it some place else beyond that, or you'd still need to re-auth for each request. If you were to store it in the session, for example, then you could do something like:
services.AddScoped<FooClient>(p =>
{
var httpClientFactory = p.GetRequiredService<IHttpClientFactory>();
var httpContextAccessor = p.GetRequiredService<IHttpContextAccessor>();
var httpClient = httpClientFactory.Create("ClientName");
var session = httpContextAccessor.HttpContext.Session;
var client = new FooClient(httpClient);
client.SetAuthToken(session["FooAuthToken"]);
});
However, even then, I'd still say it's better to pass the auth token into the method than do any of this. It's more explicit about which actions require auth versus those that do not, and you always know exactly what's coming from where.
One of your biggest problems will be the reuse of the HttpClient. This is a known problem for "pre-Core" days. Luckily, its been addressed and as of Net Core 2.1 we now have an HttpClientFactory which allows you to spin up as manage HttpClients as you need and they're handled for you as part of the framework.
https://www.stevejgordon.co.uk/introduction-to-httpclientfactory-aspnetcore
With this in mind, theres nothing stopping you from using DI to inject an IHttpClientFactory which will provide you with the necessary access to the pipeline you need. Other than that, its entirely up to you how you design the code which "manages" your access to the REST resources. Maybe some sort of Repository Pattern? (Purely guess work really without knowing your architecture etc)
I have a web api 2 web service get method. Inside I'm using HttpContext.Current.Request.UserHostAddress. When calling my controller method directly int he unit test this isn't filled in so is errors with null object. So I searched for how to fill this in and found the following which helped with that issue: Add IP address to HttpRequestMessage
However, this needs a server name to send the request to. The problem is that when tests run the VSExpress will need to be running for this API web service, which it won't be when just running the tests. On top of that even if it was it seems it picks a random port to run on so I couldn't hardcode the address like he does in the above link. How can I test my api 2 method given the above issues?
This is the line that blows up when I just test the api method
string ip = HttpContext.Current.Request.UserHostAddress;
[EDIT] Answer
Just so everyone knows here is the solution in code
public class MyController : ApiController
{
private: HttpRequestBase httpRequest;
public MyController()
{
httpRequest = new HttpRequestWrapper(HttpContext.Current.Request)
}
public MyController(HttpRequestBase http)
{
httpRequest = http;
}
public HttpResponseMessage Get()
{
string ip = httpRequest.UserHostAddress;
}
}
I use Moq in the unit test:
Mock<HttpRequestBase> httpRequestMock = new Mock<HttpRequestBase>();
httpRequestMock.Setup(x => x.UserHostAddress).Returns("127.0.0.1");
// then pass httpRequestMock.Object to my controller ctor and good to go
Decouple your controller from the HTTP context. There might be some built-in functionality to do this with which I'm unfamiliar, but one approach would be to simply inject a mockable object. Consider something like this:
public interface IRequestInformation
{
string UserHostAddress { get; }
}
public class RequestInformation : IRequestInformation
{
public string UserHostAddress
{
get { return HttpContext.Current.Request.UserHostAddress; }
}
}
Now you've abstracted the dependency on HttpContext behind an interface. If you're using dependency injection, inject that interface into your controller. If you're not, you can fake it:
// in your controller...
private IRequestInformation _request;
public IRequestInformation RequestInfo
{
get
{
if (_request == null)
_request = new RequestInformation();
return _request;
}
set { _request = value; }
}
Then use that in your controller logic:
string ip = RequestInfo.UserHostAddress;
Now in your unit tests you can supply a mock/fake/etc. for the RequestInfo property. Either create one manually or use a mocking library. If you create one manually, that's simple enough:
public class RequestInformationFake : IRequestInformation
{
public string UserHostAddress
{
get { return "some known value"; }
}
}
Then just supply that to the controller when arranging the test:
var controller = new YourController();
controller.RequestInformation = new RequestInformationFake();
// run your test
Replace your references to HttpContext by references to HttpContextBase. When in your code, initialize the HttpContextBase with a HttpContextWrapper instance, which is a the default behavior implementation in a web stack.
However in your test inject a custom HttpContextBase implementation where you implement the methods and behaviors needed by your test only.
As precised in the link:
The HttpContextBase class is an abstract class that contains the same
members as the HttpContext class. The HttpContextBase class enables
you to create derived classes that are like the HttpContext class, but
that you can customize and that work outside the ASP.NET pipeline.
When you perform unit testing, you typically use a derived class to
implement members with customized behavior that fulfills the scenario
you are testing.
Add the following method to the controller, or inject the equivalent. It uses the magic string MS_HttpContext because that's what the AspNetWebStack implementation uses for exactly the same purpose.
HttpContextBase HttpContextBase => HttpContext.Current != null
? new HttpContextWrapper(HttpContext.Current)
: (HttpContextBase)Request.Properties["MS_HttpContext"]
Replace all other uses of HttpContext.Current in the controller with HttpContextBase.
When unit testing:
var context = new Mock<HttpContextBase>();
...
controller.Request = new HttpRequestMessage();
controller.Request.Properties["MS_HttpContext"] = context.Object;
I have read other posts on this, and loads on net, but I am still unsure If what I have is fully correct..
I have use a servicehostfactory to initialise StructureMap in the appropriate service.. (based on this)
Snippet below..
public class StructureMapServiceHostFactory : ServiceHostFactory
{
public StructureMapServiceHostFactory()
{
Bootstrapper.ConfigureDependencies();
}
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
return new StructureMapServiceHost(serviceType, baseAddresses);
}
}
and the bootstrapping..
public static IContainer ConfigureDependencies()
{
if (AlreadyRegistered)
{
return ObjectFactory.Container;
}
lock (_lockThis)
{
if (AlreadyRegistered)
{
return ObjectFactory.Container;
}
BootstrapStructureMap();
AlreadyRegistered = true;
}
return ObjectFactory.Container;
}
public static void BootstrapStructureMap()
{
ObjectFactory.Initialize(x =>
{
x.AddRegistry<InfrastructureRegistry>();
});
}
public class InfrastructureRegistry : Registry
{
public InfrastructureRegistry()
{
For<Entities>().HybridHttpOrThreadLocalScoped().Use(c => new Entities());
...
The registering of my Entity Framework context is HybridHttpOrThreadLocalScoped. In the Application_EndRequest I am releasing http scoped objects which should be just the db context, as this I want per service request.
protected void Application_EndRequest(object sender, EventArgs e)
{
Bootstrapper.ReleaseAndDisposeAllHttpScopedObjects();
}
public static void ReleaseAndDisposeAllHttpScopedObjects()
{
ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects();
}
Is this the correct approach or am I missing something? This way I should not need a using statement around my context, as it should be scoped to that request, and the next request gets another one.
Main reason is that from time to time, when I access a sub object on an entity, the object is null, whereas it should nto be and I am trying to eliminate the fact that it might be a shared context..
I tried to write out the context on Application_EndRequest
var instance = StructureMap.ObjectFactory.GetInstance<AXA_Entities.Entities>(); - write to file then
and the hashCode was unique, but Calling GetInstance will get me a new instance each time I would imagine?
I think I am close on this, but an explanation of something I am possibly missing is appreciated.
Ideally I want my scope to be like this.
For<Entities>().HttpContextScoped().Use(c => new Entities());
but I get the following method as a result.
"StructureMap Exception Code: 309\nYou cannot use the HttpContextLifecycle outside of a web request. Try the HybridLifecycle instead."
unitofwork-in-wcf-using-structuremap answered what I should do.. there is other links inside so read carefully. I dont use the uow interface but the custom lifecycle is what I used in the end..
on version 2.6.4 of structuremap - latest version has changed some of the interfaces so havent upgraded yet.
For<Entities>().LifecycleIs(new WcfInstanceContextLifecycle()).Use(c
=> new Entities());