How to send pre request before every request in windows phone 7 - windows-phone-7

I want to send one pre request to my server before send every request. From that pre request I will receive the token from my server and than I have to add that token into all the request. This is the process.
I have try with some methods to achieve this. But I am facing one problem. That is, When I try to send pre request, it is processing with the current request. That mean both request going parallel.
I want to send pre request first and parse the response. After parsing the pre request response only I want to send that another request. But first request not waiting for the pre request response. Please let me any way to send pre request before all the request.
This is my code:
ViewModel:
`public class ListExampleViewModel
{
SecurityToken sToken = null;
public ListExampleViewModel()
{
GlobalConstants.isGetToken = true;
var listResults = REQ_RESP.postAndGetResponse((new ListService().GetList("xx","xxx")));
listResults.Subscribe(x =>
{
Console.WriteLine("\n\n..................................2");
Console.WriteLine("Received Response==>" + x);
});
}
}`
Constant Class for Request and Response:
`public class REQ_RESP
{
private static string receivedAction = "";
private static string receivedPostDate = "";
public static IObservable<string> postAndGetResponse(String postData)
{
if (GlobalConstants.isGetToken)
{
//Pre Request for every reusest
receivedPostDate = postData;
GlobalConstants.isGetToken = false;
getServerTokenMethod();
postData = receivedPostDate;
}
HttpWebRequest serviceRequest =
(HttpWebRequest)WebRequest.Create(new Uri(Constants.SERVICE_URI));
var fetchRequestStream =
Observable.FromAsyncPattern<Stream>(serviceRequest.BeginGetRequestStream,
serviceRequest.EndGetRequestStream);
var fetchResponse =
Observable.FromAsyncPattern<WebResponse>(serviceRequest.BeginGetResponse,
serviceRequest.EndGetResponse);
Func<Stream, IObservable<HttpWebResponse>> postDataAndFetchResponse = st =>
{
using (var writer = new StreamWriter(st) as StreamWriter)
{
writer.Write(postData);
writer.Close();
}
return fetchResponse().Select(rp => (HttpWebResponse)rp);
};
Func<HttpWebResponse, IObservable<string>> fetchResult = rp =>
{
if (rp.StatusCode == HttpStatusCode.OK)
{
using (var reader = new StreamReader(rp.GetResponseStream()))
{
string result = reader.ReadToEnd();
reader.Close();
rp.GetResponseStream().Close();
XDocument xdoc = XDocument.Parse(result);
Console.WriteLine(xdoc);
return Observable.Return<string>(result);
}
}
else
{
var msg = "HttpStatusCode == " + rp.StatusCode.ToString();
var ex = new System.Net.WebException(msg,
WebExceptionStatus.ReceiveFailure);
return Observable.Throw<string>(ex);
}
};
return
from st in fetchRequestStream()
from rp in postDataAndFetchResponse(st)
from str in fetchResult(rp)
select str;
}
public static void getServerTokenMethod()
{
SecurityToken token = new SecurityToken();
var getTokenResults = REQ_RESP.postAndGetResponse((new ServerToken().GetServerToken()));
getTokenResults.Subscribe(x =>
{
ServerToken serverToken = new ServerToken();
ServiceModel sm = new ServiceModel();
//Parsing Response
serverToken = extract(x, sm);
if (!(string.IsNullOrEmpty(sm.NetErrorCode)))
{
MessageBox.Show("Show Error Message");
}
else
{
Console.WriteLine("\n\n..................................1");
Console.WriteLine("\n\nserverToken.token==>" + serverToken.token);
Console.WriteLine("\n\nserverToken.pk==>" + serverToken.pk);
}
},
ex =>
{
MessageBox.Show("Exception = " + ex.Message);
},
() =>
{
Console.WriteLine("End of Process.. Releaseing all Resources used.");
});
}
}`

Here's couple options:
You could replace the Reactive Extensions model with a simpler async/await -model for the web requests using HttpClient (you also need Microsoft.Bcl.Async in WP7). With HttpClient your code would end up looking like this:
Request and Response:
public static async Task<string> postAndGetResponse(String postData)
{
if (GlobalConstants.isGetToken)
{
//Pre Request for every reusest
await getServerTokenMethod();
}
var client = new HttpClient();
var postMessage = new HttpRequestMessage(HttpMethod.Post, new Uri(Constants.SERVICE_URI));
var postResult = await client.SendAsync(postMessage);
var stringResult = await postResult.Content.ReadAsStringAsync();
return stringResult;
}
Viewmodel:
public class ListExampleViewModel
{
SecurityToken sToken = null;
public ListExampleViewModel()
{
GetData();
}
public async void GetData()
{
GlobalConstants.isGetToken = true;
var listResults = await REQ_RESP.postAndGetResponse("postData");
}
}
Another option is, if you want to continue using Reactive Extensions, to look at RX's Concat-method. With it you could chain the token request and the actual web request: https://stackoverflow.com/a/6754558/66988

Related

OwinOAuthProviders RefreshToken flow

I'm building a OwinOAuth (Oauth2) provider for my company to contribute here-https://github.com/TerribleDev/OwinOAuthProviders
The challenge I'm facing is that my company generates the refresh token too along with access token and provides the expiry time for both access token and refresh token. Access token expiry is set to 1hr and using Refresh token I can refresh access tokens again and again for 100 days.
Any implementations that I have seen create a RefreshTokenProvider which I don't need as my company already sends me that. The question I have here is this-
In the AuthenticationHandler class, since tokens are in memory and not saved anywhere and Oauth tokens are always generated by default, I'm not sure where the call/logic to get access tokens based on Refresh Tokens should be done.
Do I need to create a persistent store for all returned tokens and expiry and then match expiry to make a call to RefreshTokenHandler(grant_type=refresh_token) instead of AuthenticationHandler(grant_type=authorization_code) based on that?
I'm really confused here and any help with the implementation is appreciated.
EDIT-1
I have replaced my provider's name with Hidden everywhere.
Adding code for the HiddenAuthenticationHandler.
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.Owin.Infrastructure;
using Microsoft.Owin.Logging;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Infrastructure;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Owin.Security.Providers.Hidden.Provider;
using System.Net.Http.Headers;
using System.Net;
using System.Linq;
using Microsoft.Owin.Security.OAuth;
namespace Owin.Security.Providers.Hidden
{
public class HiddenAuthenticationHandler : AuthenticationHandler<HiddenAuthenticationOptions>
{
private const string XmlSchemaString = "http://www.w3.org/2001/XMLSchema#string";
private const string AuthorizationEndPoint = "https://appcenter.Hidden.com/connect/oauth2";
private const string TokenEndpoint = "https://oauth.platform.Hidden.com/oauth2/v1/tokens/bearer";
private const string UserInfoEndpoint = "https://sandbox-accounts.platform.Hidden.com/v1/openid_connect/userinfo";//"https://accounts.Hidden.com/v1/openid_connect/userinfo";//Nimisha
private const string RevokeEndpoint = "https://developer.api.Hidden.com/v2/oauth2/tokens/revoke";//Nimisha
private const string JWKSEndpoint = "https://oauth.platform.Hidden.com/op/v1/jwks";//Nimisha
private const string IssuerEndpoint = "https://oauth.platform.Hidden.com/op/v1";//Nimisha
private const string DiscoveryEndpoint = "https://developer.Hidden.com/.well-known/openid_configuration";//Nimisha
private static string refreshToken;
private static string refreshTokenExpiresIn;
private static string tokenType;
private readonly ILogger _logger;
private readonly HttpClient _httpClient;
public HiddenAuthenticationHandler(HttpClient httpClient, ILogger logger)
{
_httpClient = httpClient;
_logger = logger;
}
//public async Task GrantRefreshToken(OAuthGrantRefreshTokenContext context)
//{
// var originalClient = context.Ticket.Properties.Dictionary["as:client_id"];
// var currentClient = context.ClientId;
// if (originalClient != currentClient)
// {
// context.SetError("invalid_clientId", "Refresh token is issued to a different clientId.");
// return Task.FromResult<object>(null);
// }
// // Change auth ticket for refresh token requests
// var newIdentity = new ClaimsIdentity(context.Ticket.Identity);
// newIdentity.AddClaim(new Claim("newClaim", "newValue"));
// var newTicket = new AuthenticationTicket(newIdentity, context.Ticket.Properties);
// context.Validated(newTicket);
// return Task.FromResult<object>(null);
//}
public async Task<AuthenticationTicket> RefreshTokenAsync()
{
AuthenticationProperties properties = null;
// OAuth2 10.12 CSRF
if (!ValidateCorrelationId(properties, _logger))
{
return new AuthenticationTicket(null, properties);
}
//var requestPrefix = Request.Scheme + "://" + Request.Host;
////var redirectUri = requestPrefix + Request.PathBase + Options.CallbackPath;
//var redirectUri = "https://be97d742.ngrok.io/signin-Hidden";
// Build up the body for the token request
var body = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("grant_type", "refresh_token"),
new KeyValuePair<string, string>("refresh_token", refreshToken)
};
// Request the token
var refreshTokenResponse =
await _httpClient.PostAsync(TokenEndpoint, new FormUrlEncodedContent(body));
refreshTokenResponse.EnsureSuccessStatusCode();
var text = await refreshTokenResponse.Content.ReadAsStringAsync();
// Deserializes the token response
dynamic response = JsonConvert.DeserializeObject<dynamic>(text);
var accessToken = (string)response.access_token;
var expires = (string)response.expires_in;
//string refreshToken = null;
refreshToken = (string)response.refresh_token;
refreshTokenExpiresIn = (string)response.x_refresh_token_expires_in;
tokenType = (string)response.token_type;
return new AuthenticationTicket(null, properties);
}
protected override async Task<AuthenticationTicket> AuthenticateCoreAsync()
{
AuthenticationProperties properties = null;
try
{
string code = null;
string state = null;
var query = Request.Query;
var values = query.GetValues("code");
if (values != null && values.Count == 1)
{
code = values[0];
}
values = query.GetValues("state");
if (values != null && values.Count == 1)
{
state = values[0];
}
properties = Options.StateDataFormat.Unprotect(state);
if (properties == null)
{
return null;
}
// OAuth2 10.12 CSRF
if (!ValidateCorrelationId(properties, _logger))
{
return new AuthenticationTicket(null, properties);
}
var requestPrefix = Request.Scheme + "://" + Request.Host;
//var redirectUri = requestPrefix + Request.PathBase + Options.CallbackPath;
var redirectUri = "https://be97d742.ngrok.io/signin-Hidden";
// Build up the body for the token request
var body = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("grant_type", "authorization_code"),
new KeyValuePair<string, string>("code", code),
new KeyValuePair<string, string>("redirect_uri", redirectUri),
new KeyValuePair<string, string>("client_id", Options.ClientId),
new KeyValuePair<string, string>("client_secret", Options.ClientSecret)
};
// Request the token
var tokenResponse =
await _httpClient.PostAsync(TokenEndpoint, new FormUrlEncodedContent(body));
tokenResponse.EnsureSuccessStatusCode();
var text = await tokenResponse.Content.ReadAsStringAsync();
// Deserializes the token response
dynamic response = JsonConvert.DeserializeObject<dynamic>(text);
var accessToken = (string)response.access_token;
var expires = (string)response.expires_in;
//string refreshToken = null; //Nimisha
refreshToken = (string)response.refresh_token;
refreshTokenExpiresIn = (string)response.x_refresh_token_expires_in;
tokenType = (string)response.token_type;
// Get the Hidden user
var userRequest = new HttpRequestMessage(HttpMethod.Get, Options.Endpoints.UserInfoEndpoint );
userRequest.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
userRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
var userResponse = await _httpClient.SendAsync(userRequest, Request.CallCancelled);
userResponse.EnsureSuccessStatusCode();
text = await userResponse.Content.ReadAsStringAsync();
var user = JObject.Parse(text);
var context = new HiddenAuthenticatedContext(Context, user, accessToken, expires, refreshToken, refreshTokenExpiresIn, tokenType)
{
Identity = new ClaimsIdentity(
Options.AuthenticationType,
ClaimsIdentity.DefaultNameClaimType,
ClaimsIdentity.DefaultRoleClaimType)
};
if (!string.IsNullOrEmpty(context.Sub))
{
context.Identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, context.Sub, XmlSchemaString, Options.AuthenticationType));
}
if (!string.IsNullOrEmpty(context.GivenName))
{
string Name = "";
Name = context.GivenName;
if (!string.IsNullOrEmpty(context.FamilyName))
{
Name = Name +" " + context.FamilyName;
}
context.Identity.AddClaim(new Claim(ClaimsIdentity.DefaultNameClaimType, Name, XmlSchemaString, Options.AuthenticationType));
context.Identity.AddClaim(new Claim("urn:Hidden:name", Name, XmlSchemaString, Options.AuthenticationType));
}
if ((!string.IsNullOrEmpty(context.Email)) && (!string.IsNullOrEmpty(context.EmailVerified)))
{
if (String.Equals(context.EmailVerified, "true"))
{
context.Identity.AddClaim(new Claim(ClaimTypes.Email, context.Email, XmlSchemaString, Options.AuthenticationType));
}
}
if ((!string.IsNullOrEmpty(context.PhoneNumber)) && (!string.IsNullOrEmpty(context.PhoneNumberVerified)))
{
if (String.Equals(context.PhoneNumberVerified, "true"))
{
context.Identity.AddClaim(new Claim(ClaimTypes.MobilePhone, context.Email, XmlSchemaString, Options.AuthenticationType));
}
}
if (!string.IsNullOrEmpty(context.StreetAddress))
{
context.Identity.AddClaim(new Claim(ClaimsIdentity.DefaultNameClaimType, context.StreetAddress, XmlSchemaString, Options.AuthenticationType));
}
if (!string.IsNullOrEmpty(context.Locality))
{
context.Identity.AddClaim(new Claim(ClaimsIdentity.DefaultNameClaimType, context.Locality, XmlSchemaString, Options.AuthenticationType));
}
if (!string.IsNullOrEmpty(context.Region))
{
context.Identity.AddClaim(new Claim(ClaimsIdentity.DefaultNameClaimType, context.Locality, XmlSchemaString, Options.AuthenticationType));
}
if (!string.IsNullOrEmpty(context.PostalCode))
{
context.Identity.AddClaim(new Claim(ClaimsIdentity.DefaultNameClaimType, context.Locality, XmlSchemaString, Options.AuthenticationType));
}
if (!string.IsNullOrEmpty(context.Country))
{
context.Identity.AddClaim(new Claim(ClaimsIdentity.DefaultNameClaimType, context.Locality, XmlSchemaString, Options.AuthenticationType));
}
context.Properties = properties;
await Options.Provider.Authenticated(context);
return new AuthenticationTicket(context.Identity, context.Properties);
}
catch (Exception ex)
{
_logger.WriteError(ex.Message);
}
return new AuthenticationTicket(null, properties);
}
protected override Task ApplyResponseChallengeAsync()//Nimisha-1
{
if (Response.StatusCode != 401)
{
return Task.FromResult<object>(null);
}
//If Response is 401 then check here based on saved Expiration duration for token and refreshtoken and then make either Refresh Token call or Access Token call
//if(SavedTokenExpiryTime is not null and is >=DateTime.Now) then call RefreshToken api call
//or
//Call below
var challenge = Helper.LookupChallenge(Options.AuthenticationType, Options.AuthenticationMode);
if (challenge == null) return Task.FromResult<object>(null);
var baseUri =
Request.Scheme +
Uri.SchemeDelimiter +
Request.Host +
Request.PathBase;
var currentUri =
baseUri +
Request.Path +
Request.QueryString;
//var redirectUri =
// baseUri +
// Options.CallbackPath;//Nimisha check callback path
var redirectUri = "https://be97d742.ngrok.io/signin-Hidden";
var properties = challenge.Properties;
if (string.IsNullOrEmpty(properties.RedirectUri))
{
properties.RedirectUri = currentUri;
}
// OAuth2 10.12 CSRF
GenerateCorrelationId(properties);
// comma separated
var scope = string.Join(" ", Options.Scope);
var state = Options.StateDataFormat.Protect(properties);
//Nimisha //"https://appcenter.Hidden.com/connect/oauth2" + //Nimisha check
var authorizationEndpoint =
Options.Endpoints.AuthorizationEndpoint+
"?client_id=" + Uri.EscapeDataString(Options.ClientId) +
"&response_type=code" +
"&scope=" + Uri.EscapeDataString(scope) +
"&redirect_uri=" + Uri.EscapeDataString(redirectUri) +
"&state=" + Uri.EscapeDataString(state);
Response.Redirect(authorizationEndpoint);
return Task.FromResult<object>(null);
}
public override async Task<bool> InvokeAsync()
{
return await InvokeReplyPathAsync();
}
private async Task<bool> InvokeReplyPathAsync()
{
if (!Options.CallbackPath.HasValue || Options.CallbackPath != Request.Path) return false;
// TODO: error responses
var ticket = await AuthenticateAsync();
if (ticket == null)
{
_logger.WriteWarning("Invalid return state, unable to redirect.");
Response.StatusCode = 500;
return true;
}
var context = new HiddenReturnEndpointContext(Context, ticket)
{
SignInAsAuthenticationType = Options.SignInAsAuthenticationType,
RedirectUri = ticket.Properties.RedirectUri
};
await Options.Provider.ReturnEndpoint(context);
if (context.SignInAsAuthenticationType != null &&
context.Identity != null)
{
var grantIdentity = context.Identity;
if (!string.Equals(grantIdentity.AuthenticationType, context.SignInAsAuthenticationType, StringComparison.Ordinal))
{
grantIdentity = new ClaimsIdentity(grantIdentity.Claims, context.SignInAsAuthenticationType, grantIdentity.NameClaimType, grantIdentity.RoleClaimType);
}
Context.Authentication.SignIn(context.Properties, grantIdentity);
}
if (context.IsRequestCompleted || context.RedirectUri == null) return context.IsRequestCompleted;
var redirectUri = context.RedirectUri;
if (context.Identity == null)
{
// add a redirect hint that sign-in failed in some way
redirectUri = WebUtilities.AddQueryString(redirectUri, "error", "access_denied");
}
Response.Redirect(redirectUri);
context.RequestCompleted();
return context.IsRequestCompleted;
}
}
}

Return an HttpResponse in an APIController Method which calls a different API

I have an APIController Method as below. Basically I need to validate an API response. So it's an API call within an API call.
public class DCController : ApiController
{
[HttpPost]
public HttpResponseMessage SampleMethod(string url)
{
var uri = new Uri(url);
var baseAddress = uri.GetLeftPart(System.UriPartial.Authority);
var apiAddress = url.Replace(baseAddress + "/", "");
var responseString = string.Empty;
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(baseAddress);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = client.GetAsync(apiAddress).Result;
if (response.IsSuccessStatusCode)
{
responseString = response.Content.ReadAsStringAsync().Result;
}
}
if (!string.IsNullOrEmpty(responseString) && responseString.ToString().Validate())
{
return Request.CreateResponse(HttpStatusCode.OK, "Validated");
}
else
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, "Invalid");
}
}
Issue:
1. Request object is null in the return lines.
2. If i try creating a request object -
var request = new HttpRequestMessage();
It throws below error:
An exception of type 'System.InvalidOperationException' occurred in
System.Web.Http.dll but was not handled in user code
Additional information: The request does not have an associated
configuration object or the provided configuration was null.
Not sure what settings I need to add. I am relatively new to working with APIs. Any help is appreciated.
I could get it working by below code -
[HttpPost]
public HttpResponseMessage Get(string url)
{
string responseString = GetWebApiData(url); //Extracted the method
HttpResponseMessage response = new HttpResponseMessage();
if (!string.IsNullOrEmpty(responseString) && responseString.ToString().Validate())
{
response.ReasonPhrase = "Valid";
response.StatusCode = HttpStatusCode.OK;
}
else
{
response.ReasonPhrase = "Invalid";
response.StatusCode = HttpStatusCode.BadRequest;
}
return response;
}

backbonejs model.save method --post request params become null on the server side

Can anyone tell what am I doing wrong here???
In bankbonejs, I am trying to make a POST request. Here is my code: Im using tomcat server.
$.fn.serializeObject = function() {
var o = {};
var a = this.serializeArray();
$.each(a, function() {
if (o[this.name] !== undefined) {
if (!o[this.name].push) {
o[this.name] = [o[this.name]];
}
o[this.name].push(this.value || '');
} else {
o[this.name] = this.value || '';
}
});
return o;
};
saveDetails: function (ev) {
var abcDetails= $(ev.currentTarget).serializeObject();
var abc= new ABC();
bank.save(abcDetails, {
success: function (abc) {
router.navigate('', {trigger:true});
}
});
return false;
}
Call goes to the server side (Tomcat) but the post request params are coming as null. I have checked var abcDetails just before requesting the save has the values populated correctly. Also, checked by sending post request thru PostMaster to make sure that values are passed from the client side correctly. However, on the server side these posted request params are null. I am some how stuck here.vAppreciate help in this regard.
Server Side
.
#RequestMapping(value = { "/postedValues" }, method = RequestMethod.POST)
public String getpostedValues( HttpServletResponse response, HttpServletRequest request) throws Exception {
JSONArray jsonarray = new JSONArray();
JSONObject jsonobj = new JSONObject();
String _id = StringEscapeUtils.escapeHtml4(request.getParameter("id"));
String col1= StringEscapeUtils.escapeHtml4(request.getParameter("col1"));
String col2= StringEscapeUtils.escapeHtml4(request.getParameter("col2"));
Also,
Enumeration paramaterNames = request.getParameterNames();
while(paramaterNames.hasMoreElements() ) {
System.out.println(paramaterNames.nextElement());
}--> observation:does not go inside the while loop

Resharpe.portable get Twitter request token

Hello i'm doing an xamarin.form application and i'm implementing the twitter login using oauth.
I have problem to get the request_token folowing the link:
https://dev.twitter.com/oauth/reference/post/oauth/request_token
using restsharp.portable for the request POST i arrive at this point:
public async void GetTwitterToken()
{
try
{
TwitterLogin tw = new TwitterLogin();
RestClient client = new RestClient("https://api.twitter.com");
RestRequest request = new RestRequest("/oauth/request_token", Method.POST);
client.Authenticator = OAuth1Authenticator.ForRequestToken(tw.oauth_consumer_key, tw.oauth_consumer_secret);
IRestResponse response = await client.Execute(request);
}
catch (Exception e)
{
}
}
Parameter "response" it's ok but i'don't know how to parse to get token (it's not json).
i have seen this example:
public void GetRequestToken()
{
var client = new RestClient("https://api.twitter.com"); // Note NO /1
client.Authenticator = OAuth1Authenticator.ForRequestToken(
_consumerKey,
_consumerSecret,
"http://markashleybell.com" // Value for the oauth_callback parameter
);
var request = new RestRequest("/oauth/request_token", Method.POST);
var response = client.Execute(request);
var qs = HttpUtility.ParseQueryString(response.Content);
_token = qs["oauth_token"];
_tokenSecret = qs["oauth_token_secret"];
}
But i don't have HttpUtility.ParseQueryString(response.Content) whith xamarin.form framework

ASP.Net Web Api Url.Link not returning a UriString in unit test

I Have the following test:
[Test]
public void Add_New_Group_Should_Return_StatusCode_Created_And_A_Header_Location_To_The_New_Group()
{
var newGroup = new GroupData { ID = 1, UserID = 1, Name = "Group 1", Description = "Description 1" };
var fakeGroupDAL = A.Fake<IGroupDAL>();
var contactGroupsController = new ContactGroupsController(fakeGroupDAL);
SetupControllerForTests(contactGroupsController, HttpMethod.Post);
var response = contactGroupsController.AddGroup(new ContactGroupApiRequest(), newGroup);
Assert.IsTrue(response.StatusCode == HttpStatusCode.Created, "Should have returned HttpStatusCode.Created");
}
Which calls the following configuration method:
private static void SetupControllerForTests(ApiController controller, HttpMethod httpMethod)
{
var config = new HttpConfiguration();
var request = new HttpRequestMessage(httpMethod, "http://localhost/contactgroups");
var route = config.Routes.MapHttpRoute("ContactGroupsApi", "{controller}/{action}/{request}", new { request = RouteParameter.Optional });
var routeData = new HttpRouteData(route, new HttpRouteValueDictionary { { "controller", "contactgroups" } });
controller.ControllerContext = new HttpControllerContext(config, routeData, request);
controller.Request = request;
controller.Request.Properties[HttpPropertyKeys.HttpConfigurationKey] = config;
}
I'm trying to test the following action method:
[HttpPost]
public HttpResponseMessage AddGroup([FromUri]ApiRequest req, [FromBody] GroupData contactGroup)
{
if(ModelState.IsValid && contactGroup !=null)
{
_groupDal.AddGroup(contactGroup);
contactGroup.Name = HttpUtility.HtmlEncode(String.Format("{0} - {1}", contactGroup.Name, contactGroup.Description));
var response = new HttpResponseMessage(HttpStatusCode.Created) { Content = new StringContent(contactGroup.Name) };
var uriString = Url.Link("ContactGroupsApi", new { controller = "contactgroups", action = "Group", UserId = contactGroup.UserID, GroupId = contactGroup.ID});
response.Headers.Location = new Uri(uriString);
return response;
}
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
The action method works perfectly well when called normally, but fails under test because the call to Url.Link returns null.
var uriString = Url.Link("ContactGroupsApi", new { controller = "contactgroups", action = "Group", UserId = contactGroup.UserID, GroupId = contactGroup.ID});
All this code is based very closely on the following article: Unit test ASP.NET Web Api
I suspect that when running under test there is insufficient route table info. Any idea what I'm doing wrong?
I fixed my tests by adding the HttpRouteData to the HttpRouteDataKey property of the controller's HttpRequestMessage. Like this:
controller.Request.Properties[HttpPropertyKeys.HttpRouteDataKey] = routeData;

Resources