Please see the code below. Using in-memory hosting of httpclient, and Passing httpclient object to controller in order to unit test action method. But I am getting "Internal Server Error" ReasonPhrase upon HttpResponseMessage response =_httpClient.GetAsync. Please help me, is it correct approach?
private readonly HttpClient _httpClient;
public SecurityMfMvcController(HttpClient httpClient)
{
this._httpClient = httpClient;
}
[HttpGet]
public ActionResult GetSecuritiesMfs()
{
try
{
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response =
_httpClient.GetAsync(ConfigurationManager.AppSettings["ApiUrl"] + "SecuritiesWebApiMf").Result;
response.EnsureSuccessStatusCode();
List<SecurityMutualFundDto> list =
response.Content.ReadAsAsync<List<SecurityMutualFundDto>>().Result;
return View("SecuritiesMf", list);
}
catch (Exception ex)
{
return View("Error", ex.Message);
}
}
//Unit Test Method for this Action
[Test]
public void TestActionGetSecuritiesMfs()
{
var config = new HttpConfiguration()
{
IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always
};
//use the configuration that the web application has defined
WebApiConfig.Register(config);
HttpServer server = new HttpServer(config);
//create a client with a handler which makes sure to exercise the formatters
using (var client = new HttpClient(new InMemoryHttpContentSerializationHandler(server)))
{
System.Uri uri = new System.Uri("http://localhost:55893/api/");
client.BaseAddress = uri;
var controller = new SecurityMfMvcController(client);
var result = controller.GetSecuritiesMfs();
Assert.IsNotNull(result);
}
}
//MessageHandler
public class InMemoryHttpContentSerializationHandler : DelegatingHandler
{
public InMemoryHttpContentSerializationHandler(HttpMessageHandler innerHandler)
: base(innerHandler)
{
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
request.Content = await ConvertToStreamContentAsync(request.Content);
HttpResponseMessage response = await base.SendAsync(request, cancellationToken);
response.Content = await ConvertToStreamContentAsync(response.Content);
return response;
}
private async Task<StreamContent> ConvertToStreamContentAsync(HttpContent originalContent)
{
if (originalContent == null)
{
return null;
}
StreamContent streamContent = originalContent as StreamContent;
if (streamContent != null)
{
return streamContent;
}
MemoryStream ms = new MemoryStream();
await originalContent.CopyToAsync(ms);
// Reset the stream position back to 0 as in the previous CopyToAsync() call,
// a formatter for example, could have made the position to be at the end
ms.Position = 0;
streamContent = new StreamContent(ms);
// copy headers from the original content
foreach (KeyValuePair<string, IEnumerable<string>> header in originalContent.Headers)
{
streamContent.Headers.TryAddWithoutValidation(header.Key, header.Value);
}
return streamContent;
}
}
You could mock your http request pipeline and test your action:
var mockHttpRequest = new Mock<HttpRequestMessage>(new object[] {new HttpMethod("GET"), "www.someuri.com"});
var mockHttpConfig = new Mock<HttpConfiguration>();
var mockRouteData = new Mock<IHttpRouteData>();
var mockHttpContext =
new Mock<HttpControllerContext>(new object[]
{mockHttpConfig.Object, mockRouteData.Object, mockHttpRequest.Object});
Then set your controller object with these values:
var controller = new YourController();
controller.ControllerContext = mockHttpContext.Object;
controller.Request = controller.ControllerContext.Request;
response = controller.SecuritiesMF();
and you could check your response as follows:
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
I got it working, correct me in case of anything wrong here. I have to create a "FakeHttpMessageHandler" as below and the content type to match System.Net.Http.StreamContent for application/json content type. the below code is working to unit test mvc action method using httpclient to call WebAPI. however I need to double check whether this is the right approach for unit test, will review further.
[Test]
public void TestActionMethodSelectByIdUsingFakeHandler()
{
var uobj = new UnitTestForApiController();
var testobj= uobj.GetsecuritiesMfsList();
MemoryStream stream = new MemoryStream();
IFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, testobj);
var response = new HttpResponseMessage(HttpStatusCode.OK)
{Content = new StreamContent(stream)};
using (var httpClient = new HttpClient(new FakeHandler
{
Response = response,
InnerHandler = new HttpClientHandler()
}))
{
System.Uri uri = new System.Uri("http://localhost:55893/api/");
httpClient.BaseAddress = uri;
var controller = new SecuritiesMfMvcController(httpClient);
var result = controller.Select(2155) as ViewResult;
Assert.IsNotNull(result);
Assert.AreEqual(result.ViewName,"Select");
Assert.AreEqual(result.Model, testobj.FirstOrDefault());
}
//FakeHandler class goes as below
public class FakeHandler : DelegatingHandler
{
public HttpResponseMessage Response { get; set; }
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
CancellationToken cancellationToken)
{
return Task.Factory.StartNew(() => Response, cancellationToken);
}
}
//We can also have logic for abstracting appropriate StreamContent Creation into FakeContent class like below:
public class FakeHttpContent : HttpContent
{
public object Content { get; set; }
public FakeHttpContent(object content)
{
Content = content;
}
protected async override Task SerializeToStreamAsync(Stream stream,
TransportContext context)
{
MemoryStream ms = new MemoryStream();
IFormatter formatter = new BinaryFormatter();
formatter.Serialize(ms, Content);
await ms.CopyToAsync(stream);
}
protected override bool TryComputeLength(out long length)
{
length = Content.ToString().Length;
return true;
}
}
Related
I'm using HttpMessageHandler to log Http Request and Response. If internet connection is not available I get HttpRequestException, but this Exception is not catched (try catch not working). If I don't use HttpMessageHandler Exception is catched.
Method with try catch :
public JObject Get()
{
string url = "/...";
try
{
using (var httpClientHandler = new HttpClientHandler())
{
httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert,
chain, errors) =>
{ return true; };
using (var client = new HttpClient(new LoggingHandler(httpClientHandler)))
{
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue(CONTENT_TYPE_JSON));
var byteArray = Encoding.ASCII.GetBytes("");
client.DefaultRequestHeaders.Authorization = new
System.Net.Http.Headers.AuthenticationHeaderValue("Basic",
Convert.ToBase64String(byteArray));
HttpResponseMessage response = client.GetAsync(url).Result;
response.EnsureSuccessStatusCode();
var json = response.Content.ReadAsStringAsync().Result;
JObject rss = JObject.Parse(json);
return rss;
}
}
}
catch(HttpRequestException ex)
{
//Catch not working
return null;
}
}
HttpMessageHandler :
public class LoggingHandler : DelegatingHandler
{
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(typeof(LoggingHandler));
public LoggingHandler(HttpMessageHandler innerHandler)
: base(innerHandler)
{
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
CancellationToken cancellationToken)
{
HttpResponseMessage response = null;
Loging("Request:");
Loging(request.ToString());
if (request.Content != null)
{
Loging(await request.Content.ReadAsStringAsync());
}
Loging("");
response = await base.SendAsync(request, cancellationToken);
Loging("Response:");
Loging(response.ToString());
if (response.Content != null)
{
Loging(await response.Content.ReadAsStringAsync());
}
Loging("");
return response;
}
private void Loging(string message)
{
Debug.WriteLine(message);
log.Info(message);
}
}
Why is it happining?
I added a consumer to observe routing slip events, but doesn't work as expected. RoutingSlipCompleted consumer is always triggered, RoutingSlipActivityCompleted and RoutingSlipActivityFaulted consumer are never triggered. This is my consumer code.
public abstract class RoutingSlipExecuteActivityResponseProxy<TRequest, TResponse, TFaultResponse> :
IConsumer<RoutingSlipActivityCompleted>,
IConsumer<RoutingSlipActivityFaulted>,
IConsumer<RoutingSlipCompleted>
where TRequest : class
where TResponse : class
where TFaultResponse : class
{
public abstract string ActivityName { get; }
public async Task Consume(ConsumeContext<RoutingSlipActivityCompleted> context)
{
if(context.Message.ActivityName!= ActivityName)
{
return;
}
var request = context.Message.GetVariable<TRequest>("Request");
var requestId = context.Message.GetVariable<Guid>("RequestId");
Uri responseAddress = null;
if (context.Message.Variables.ContainsKey("ResponseAddress"))
responseAddress = context.Message.GetVariable<Uri>("ResponseAddress");
if (responseAddress == null)
throw new ArgumentException($"The response address could not be found for the faulted routing slip: {context.Message.TrackingNumber}");
var endpoint = await context.GetResponseEndpoint<TResponse>(responseAddress, requestId).ConfigureAwait(false);
var response = await CreateResponseMessage(context, request);
await endpoint.Send(response).ConfigureAwait(false);
}
public async Task Consume(ConsumeContext<RoutingSlipActivityFaulted> context)
{
if (context.Message.ActivityName != ActivityName)
{
return;
}
var request = context.Message.GetVariable<TRequest>("Request");
var requestId = context.Message.GetVariable<Guid>("RequestId");
Uri faultAddress = null;
if (context.Message.Variables.ContainsKey("FaultAddress"))
faultAddress = context.Message.GetVariable<Uri>("FaultAddress");
if (faultAddress == null && context.Message.Variables.ContainsKey("ResponseAddress"))
faultAddress = context.Message.GetVariable<Uri>("ResponseAddress");
if (faultAddress == null)
throw new ArgumentException($"The fault/response address could not be found for the faulted routing slip: {context.Message.TrackingNumber}");
var endpoint = await context.GetFaultEndpoint<TResponse>(faultAddress, requestId).ConfigureAwait(false);
var response = await CreateFaultedResponseMessage(context, request, requestId);
await endpoint.Send(response).ConfigureAwait(false);
}
protected abstract Task<TResponse> CreateResponseMessage(ConsumeContext<RoutingSlipActivityCompleted> context, TRequest request);
protected abstract Task<TFaultResponse> CreateFaultedResponseMessage(ConsumeContext<RoutingSlipActivityFaulted> context, TRequest request, Guid requestId);
public Task Consume(ConsumeContext<RoutingSlipCompleted> context)
{
throw new NotImplementedException();
}
}
My activity has no additional configuration, basically it is written according to the documentation.
You might want to check out this sample, which uses the RequestResponseProxy to handle a request via routing slip, and then generates the response based upon the RoutingSlipCompleted/RoutingSlipFaulted events.
I have a hub that does not convert the token located at Authorization:Bearer eyjsdalfsadlfjffdafs... in the request header to an identity. The rest of the API works fine with standard http verbs however for some reason SignalR is not authorizing the token into a user.
public class ChatHub : Hub
{
[Authorize]
public override Task OnConnected()
{
// error context.user.identity.name =""
var userId = int.Parse(Context.User.Identity.Name);
return base.OnConnected();
}
....
}
Startup.cs
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.MapSignalR();
}
}
JwtHandler - this part of the filter is not called when the client connects to the hub even though onConnect() is attributed with [Authorize]
public class JwtHandler : DelegatingHandler
{
private const string ISSUER = "Issuer";
private const string AUDIENCE = "Audience";
protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
byte[] key = Convert.FromBase64String("SecretKey");
try
{
var headers = request.Headers;
if(headers.Authorization != null)
{
if(headers.Authorization.Scheme.Equals("Bearer"))
{
string jwt = request.Headers.Authorization.Parameter;
JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
TokenValidationParameters parms = new TokenValidationParameters()
{
ValidAudience = AUDIENCE,
ValidIssuers = new List<string>(){ISSUER},
IssuerSigningToken = new BinarySecretSecurityToken(key),
};
SecurityToken validated = new JwtSecurityToken(jwt);
var principal = tokenHandler.ValidateToken(jwt, parms,out validated);
Thread.CurrentPrincipal = principal;
if(HttpContext.Current !=null)
{
HttpContext.Current.User = principal;
}
}
}
var response = await base.SendAsync(request, cancellationToken);
if(response.StatusCode == HttpStatusCode.Unauthorized)
{
response.Headers.WwwAuthenticate.Add(new AuthenticationHeaderValue("Bearer", "error=\"invalid_token\""));
return response;
}
return response;
}catch (Exception)
{
var response = request.CreateResponse(HttpStatusCode.Unauthorized);
response.Headers.WwwAuthenticate.Add(new AuthenticationHeaderValue("Bearer", "error=\"invalid_token\""));
return response;
}
}
}
Try validating the jwt token in the OWIN middleware. In your Startup.cs add:
public void Configuration(IAppBuilder app)
{
app.UseJwtBearerAuthentication(
new Microsoft.Owin.Security.Jwt.JwtBearerAuthenticationOptions() {
AllowedAudiences = new string[] { ALLOWEDAUDIENCE },
IssuerSecurityTokenProviders = new[] {
new SymmetricKeyIssuerSecurityTokenProvider(ISSUER, System.Convert.FromBase64String(cKey))
}
});
app.MapSignalR();
}
I try to realise logging in my application. And I need login before page starts loading because when all is ok I go to secondpage, and if not to firstpage. To do this I set WMAppManifest like this:
<DefaultTask Name="_default" NavigationPage="" />
And when i execute my async method , paralel application start load page but it is empty and so my application freezes.
How look my Application_Launching:
private async void Application_Launching(object sender, LaunchingEventArgs e)
{
bool logged = await LogIn("login", "pass");
Uri nUri = null;
if (logged)
{
nUri = new Uri("/SecondPage.xaml", UriKind.Relative);
}
else
{
nUri = new Uri("/FirstPage.xaml", UriKind.Relative);
}
((App)Application.Current).RootFrame.Navigate(nUri);
}
async method LogIn:
private async Task<bool> LogIn(string login, string password)
{
string str_login_number = login;
string str_login_pass = password;
JObject jo = new JObject();
jo.Add("number", str_login_number);
jo.Add("pass", str_login_pass);
JsonWorker jWorker = new JsonWorker();
var response = await jWorker.sendJSON("url", jo);
string str_responseformjson = await jWorker.getJSON(response);
jo = JObject.Parse(str_responseformjson);
if (jo["response"].ToString().Equals("ok"))
{
return true;
}
else
{
return false;
}
}
This is code of my class JsonWorker:
class JsonWorker
{
public async Task<HttpWebResponse> sendJSON(string requestUrl, JObject jsonObjesct)
{
HttpWebRequest request = (HttpWebRequest) WebRequest.Create(requestUrl);
request.ContentType = "text/plain; charset=utf-8";
request.Method = "POST";
byte[] jsonAsBytes = Encoding.UTF8.GetBytes(jsonObjesct.ToString());
Stream x = await request.GetRequestStreamAsync();
await x.WriteAsync(jsonAsBytes, 0, jsonAsBytes.Length);
x.Close();
HttpWebResponse response = (HttpWebResponse)(await request.GetResponseAsync());
return response;
}
public async Task<string> getJSON(
HttpWebResponse response)
{
var stream = response.GetResponseStream();
var sr = new StreamReader(stream);
string str_responsefromjson = await sr.ReadToEndAsync();
sr.Close();
stream.Close();
return str_responsefromjson;
}
}
Plese help.
I have the some workflow in one of my apps. I solved this by using a custom UriMapper. Read this Stackoverflow answer for more info.
Here's is the basics.
The UriMapper handles which page to navigate to based on if the user has already entered correct login credentials. Your Activated and Launching events in the app will always Login if proper credentials have been given before.
private void Application_Launching(object sender, LaunchingEventArgs e)
{
RootFrame.UriMapper = new LoginUriMapper();
if (AppSettings.HasLoginInfo)
{
Login();
}
}
private void Application_Activated(object sender, ActivatedEventArgs e)
{
if (e.IsApplicationInstancePreserved == false)
{
// tombstoned! Need to restore state
RootFrame.UriMapper = new LoginUriMapper();
if (AppSettings.NotLoggedIn)
{
Login();
}
}
}
Your MainPage will handle logic if the login fails and then navigate backwards to a login page. When you navigate to the login page always remember to remove any entries from the navigation stack
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
while(NavigationService.CanGoBack)
{
NavigationService.RemoveBackEntry();
}
}
Sorry, it's questions already was on stackoverflow, but I don't found answer. Maybe it's classic, but I can't understand, how to solve this problem :(
I have Singletone class for working with web service:
public sealed class GYAccessService
{
static GYAccessService instance = null;
static readonly object padlock = new object();
public string Atoken { get; set; }
public string Login { get; set; }
public string Password { get; set; }
public string Uid { get; set; }
const string UrlRequest = "http://site.html";
private GYAccessService()
{
}
public static GYAccessService Instance
{
get
{
lock (padlock)
{
if (instance == null)
{
instance = new GYAccessService();
}
return instance;
}
}
}
public void sendPost(string postData)
{
PostData = "request=" + postData;
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(UrlRequest);
webRequest.Method = "POST";
webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.Accept = "application/json";
webRequest.AllowAutoRedirect = true;
// Start the request
webRequest.BeginGetRequestStream(new AsyncCallback(getRequestStreamCallback), webRequest);
}
private void getRequestStreamCallback(IAsyncResult asynchronousResult)
{
HttpWebRequest webRequest = (HttpWebRequest)asynchronousResult.AsyncState;
// End the stream request operation
Stream postStream = webRequest.EndGetRequestStream(asynchronousResult);
byte[] byteArray = Encoding.UTF8.GetBytes(PostData);
// Add the post data to the web request
postStream.Write(byteArray, 0, byteArray.Length);
postStream.Close();
// Start the web request
webRequest.BeginGetResponse(new AsyncCallback(getResponseCallback), webRequest);
}
private void getResponseCallback(IAsyncResult asynchronousResult)
{
try
{
HttpWebRequest webRequest = (HttpWebRequest)asynchronousResult.AsyncState;
HttpWebResponse response;
// End the get response operation
response = (HttpWebResponse)webRequest.EndGetResponse(asynchronousResult);
Stream streamResponse = response.GetResponseStream();
StreamReader streamReader = new StreamReader(streamResponse);
var Response = streamReader.ReadToEnd();
streamResponse.Close();
streamReader.Close();
response.Close();
using (MemoryStream stream = new MemoryStream(Encoding.Unicode.GetBytes(Response)))
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(ServiceResponse));
ServiceResponse res = (ServiceResponse)serializer.ReadObject(stream);
// I want to return res in main thread
}
}
catch (WebException e)
{
// Error treatment
ServiceResponse err = new ServiceResponse();
err.Message = e.Message;
}
}
public string getRequestString(string model, string method, Params parametrs, string auth = null)
{
Function func = new Function();
func.Model = model;
func.Method = method;
func.Params = parametrs;
ServiceRequest req = new ServiceRequest() { Function = func };
string json = JsonConvert.SerializeObject(req);
ServiceResponse deserializedProduct = JsonConvert.DeserializeObject<ServiceResponse>(json);
return json;
}
}
I have call sendPost() in main thread, I want to return response in this function.
GYAccessService gy = GYAccessService.Instance;
gy.sendPost(postData);
//I want to use the response here
But in WP 7 HttpWebRequest has not GetResponse, only BeginGetResponse. I use callback and don't know how can I return response from callback. I put up with it, I can set property response my Singletone and get it after end async callback, but I don't know how can I block async callback. It's really problem, I try to use WaitOne()/Set() - don't help me, my app just frozen. I try to use IAsyncResult handle, but not success. How can I wait end to work async callback? Thanks in advance!
You need to use the EndGetResponse method and process the result in it. It is asynchronous, so you will not be able to immediately get the result after you call gy.sendPost(postData);, you have to use it as a call back.
If I may suggest, there is a simpler way for such HTTP calls, use RestSharp. It is a great and easy to use library that also works with Windows Phone.