My application is an ASP.NET Core 1.0 Web API.
I would like to test my controllers
with the TestServer
.
I have a controller
class decorated with the Authorize
attribute.
If Iam testing the controller without being decorated with theAuthorize
attribute, eveything works fine. Therefore my TestServer
setup is correct.
Iam doing the following to set the AuthenticationHeader
:
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", this.RequestToken(client).Result);
and request the Bearer-Token from my TestServer
:
private async Task<string> RequestToken(HttpClient client)
{
var requestTokenUri = "secret";
var tokenModel = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("tokendata", "secret"),
new KeyValuePair<string, string>("tokendata", "secret"),
new KeyValuePair<string, string>("tokendata", "secret"),
new KeyValuePair<string, string>("tokendata", "secret")
};
var tokenPostData = new FormUrlEncodedContent(tokenModel);
var tokenRequestResult = await client.PostAsync(requestTokenUri, tokenPostData);
tokenRequestResult.EnsureSuccessStatusCode();
var body = JObject.Parse(tokenRequestResult.Content.ReadAsStringAsync().Result);
var token = (string)body["access_token"];
return token;
}
This also works. If i print the Result of RequestToken(HttpClient)
it gives me a valid Bearer token
and the call tokenRequestResult.EnsureSuccessStatusCode();
also works.
Now, if I then decorate my controllers with Authorize
and try to test my controllers like this (snipped) it fails:
[TestMethod]
public async Task ShouldDoSomething()
{
// Arrange
var data = JsonConvert.SerializeObject("Just some data");
// Test
var response = await this.client.PostAsync(this.requestUri, jsonContent);
// Assert
response.EnsureSuccessStatusCode();
}
remember: this works, if the controller is not decorated with the Authorize
attribute.
But if Iam doing this with the Bearer-token
and the AuthenticationHeadervalue
, Iam getting the following error, as soon as its calling await this.client.PostAsync(this.requestUri, jsonContent);
:
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware:Error: Exception occurred while processing message.System.InvalidOperationException: IDX10803: Unable to obtain configuration from: 'http://localhost:5000/.well-known/openid-configuration'. ---> System.IO.IOException: IDX10804: Unable to retrieve document from: 'http://localhost:5000/.well-known/openid-configuration'. ---> System.Net.Http.HttpRequestException: An error occurred while sending the request. ---> System.Net.Http.WinHttpException: Die Serververbindung konnte nicht hergestellt werden at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Net.Http.WinHttpHandler.d__105.MoveNext() --- End of inner exception stack trace ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Net.Http.HttpClient.d__58.MoveNext() --- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.d__8.MoveNext() --- End of inner exception stack trace ---
at Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.d__8.MoveNext() --- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectConfigurationRetriever.d__3.MoveNext() --- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.IdentityModel.Protocols.ConfigurationManager`1.d__24.MoveNext() --- End of inner exception stack trace ---
at Microsoft.IdentityModel.Protocols.ConfigurationManager`1.d__24.MoveNext() --- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.d__1.MoveNext() Ausnahme ausgelöst: "System.InvalidOperationException" in System.Private.CoreLib.ni.dll Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 2204.6107ms 200
I tried to set the BackchannelHttpHandler
from the JWTBearerOptions
to the one i get from the TestServer
. But this is not possible since I need a WebHostBuilder
object to create my TestServer
:
protected HttpClient GetClient(IWebHostBuilder builder)
{
if (builder == null)
{
builder = new WebHostBuilder().UseContentRoot(GetDirPath())
.UseStartup<Startup>()
.UseEnvironment("Development")
.ConfigureServices(services =>
{
services.AddTransient<IAuthRepo, TestAuthRepo>();
services.AddTransient<IOtherRepo, TestOtherRepo>();
});
}
var server = new TestServer(builder);
...
Now how should I set the BackChannelHandler
inside the process of creating the TestServer
, without having a TestServer
yet?
Can anyone help me?
Thank you