Today i found very strange behavior in WP7.5/7.8
I am implementing authentification, i have to make post request, after that i will be redirected to result page.
In WP8 i am getting result page, after redirect. In WP7.5/7.8 - i am getting redirect result (StatusCode - 302).
public void MakeRequest() {
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(Consts.Url);
request.AllowAutoRedirect = true;
request.Method = "POST";
request.Headers[HttpRequestHeader.Cookie] = cookie;
request.BeginGetResponse(new AsyncCallback(ProcessRequest), request);
}
Process response
private void ProcessRequest(IAsyncResult callbackResult) {
HttpWebRequest myRequest = (HttpWebRequest)callbackResult.AsyncState;
using (HttpWebResponse myResponse = (HttpWebResponse)myRequest.EndGetResponse(callbackResult)) {
if (myResponse.StatusCode != HttpStatusCode.OK) {
RaiseConnectionError(string.Format("Response from server {0}\n{1}", myResponse.StatusCode, myResponse.StatusDescription));
return;
}
}
}
This situation i noticed in backed in current project. When i created the same situation on my backed using ASP.NET MVC,
[HttpPost]
public ActionResult Redirect() {
return RedirectToAction("Index");
}
// index returns simple view
it worked for both WP7.5 & 8. It's strange, because backend works fine for iOS and Android.
I saw similar questions, where guys recommends to use custom UserAgent (like normal browser), but it did not work for me.
Related
I am facing a weird problem. In my Azure mobile app, I added a plain vanilla webapi controller with standard http verbs get, put etc. Now on my localhost everything is working fine. but when I deploy this to my azurewebsite. and call using Post man. the PUT request gets mapped to GET code. I tested using Postman, fiddler.
I am sure I am missing sth, but couldn't figure it out, checked the route, tried multiple options, but just couldn't figure out. Same is true with DELETE and POST. below is the sample code
[MobileAppController]
public class TestController : BaseController
{
// GET: api/Test
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET: api/Test/5
public string Get(int id)
{
return "value";
}
// POST: api/Test
[Route("api/test")]
public async Task<string> Post([FromBody]string value)
{
await Task.Delay(100);
return "post: " + value;
}
// PUT: api/Test/5
[Route("api/test/{id}")]
public async Task<string> Put(int id, [FromBody]string value)
{
await Task.Delay(100);
return "put: " + value;
}
// DELETE: api/Test/5
[Route("api/test/{id}")]
public async Task<string> Delete(int id)
{
await Task.Delay(100);
return "delete: " + id;
}
You are mixing routing via WebAPI and routing via Mobile Apps, and they are conflicting. Pick one. For this application, I'd suggest removing the MobileAppController attribute and just going with the WebAPI routing.
Make sure you are making request via SSL i.e. your url should be starting from https.
when I was using Postman, my url was starting with "http" and any POST/PUT/DELETE request gets mapped to GET. and if I change it to "https" everything just works as expected.
Reccently, I am working on a project in Windows Phone. and In this project, to validate a user, I need to check at 3 web API, the logic is like below:
Step 1: access web api 1 to get the token
Step 2: access web api 2 to get the username/password by the token retrieved in Step 1
Step 3: access web API 3 to validate the user name/password in step 2
you can see we need to access those 3 API in order. as well know, window phone now access the network asynchronously, which causes a big challenge on make those API access in order, and which make the soure code hard to maintainace.
I also consider the synchronous source code like below, but I found there are some problems to access the network,many exeption will be thrown. For example, when an exception is thrown, I try to use asynchronous web request to access the same URL, it is OK. I am strugglig in it now. And I have to introduce thread to call it to avoid to block the UI thread.
internal static class HttpWebRequestExtensions
{
public const int DefaultRequestTimeout = 60000;
public static bool IsHttpExceptionFound = false;
public static WebResponse GetResponse(this WebRequest request, int nTimeOut = DefaultRequestTimeout)
{
var dataReady = new AutoResetEvent(false);
HttpWebResponse response = null;
var callback = new AsyncCallback(delegate(IAsyncResult asynchronousResult)
{
try
{
response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
dataReady.Set();
}
catch(Exception e)
{
IsHttpExceptionFound = true;
}
});
request.BeginGetResponse(callback, request);
if (dataReady.WaitOne(nTimeOut))
{
return response;
}
return null;
}
public static WebResponse PostRequest(this HttpWebRequest request, String postData, int nTimeOut = DefaultRequestTimeout)
{
var dataReady = new AutoResetEvent(false);
HttpWebResponse response = null;
var callback = new AsyncCallback(delegate(IAsyncResult asynchronousResult)
{
Stream postStream = request.EndGetRequestStream(asynchronousResult); //End the operation.
byte[] byteArray = Encoding.UTF8.GetBytes(postData); //Convert the string into a byte array.
postStream.Write(byteArray, 0, postData.Length); //Write to the request stream.
postStream.Close();
dataReady.Set();
});
request.BeginGetRequestStream(callback, request);
if (dataReady.WaitOne(nTimeOut))
{
response = (HttpWebResponse)request.GetResponse(nTimeOut);
if (IsHttpExceptionFound)
{
throw new HttpResponseException("Failed to get http response");
}
return response;
}
return null;
}
}
Any suggestion on using asynchronous web request to solve my case?
There's an example here of using asynchronous web services in a chained manner to call the Microsoft Translator service on WP7
Maybe it will give you some pointers?
http://blogs.msdn.com/b/translation/p/wp7translate.aspx
I've been racking my brain for a couple of days now on how to approach a new requirement.
I have two websites. The first one lets the user fill out an application. The second website is an internal website use to manage the users applications. I need to develop a "web service" that sends the application data from website 1 to website 2 and return a response to website 2 of success or failure. I have never done a web service before and I'm a bit confused on where to start. I've been reading various examples online but they all seem to be just a starting point for building a webservice... no specific examples.
So for posting the data website 1, what would my controller method look like? Do I use Json to post the data to website 2? What would and example of that look like? Is there some form of redirect in the method that points to website 2?
So for posting the response back to website 2 what would that controller method look like? I assume I would use Json again to send the response back to website 1? Is there some form of redirect in the method that points back to website 1?
I would use JSON and POST the application to the web service.
First I am assuming the application data is contained in some type of object. Use JSON.Net to serialize the object into JSON. It will look something like the following code.
var application = new Application();
string serializedApplication = JsonConvert.Serialize(application);
Second is to POST the code your endpoint(webservice, mvc action). To this you'll need to make a HTTPRequest to the endpoint. The following code is what I use to make to POST the code.
public bool Post(string url, string body)
{
//Make the post
ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true;
var bytes = Encoding.Default.GetBytes(body);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
Stream stream = null;
try
{
request.KeepAlive = false;
request.ContentLength = bytes.Length;
request.ContentType = "application/x-www-form-urlencoded";
request.Timeout = -1;
request.Method = "POST";
stream = request.GetRequestStream();
stream.Write(bytes, 0, bytes.Length);
}
finally
{
if (stream != null)
{
stream.Flush();
stream.Close();
}
}
bool success = GetResponse(request);
return success;
}
public bool GetResponse(HttpWebRequest request)
{
bool success;
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
using (Stream responseStream = response.GetResponseStream())
{
if (response.StatusCode != HttpStatusCode.OK && response.StatusCode != HttpStatusCode.Created)
{
throw new HttpException((int)response.StatusCode, response.StatusDescription);
}
var end = string.Empty;
using (StreamReader reader = new StreamReader(responseStream))
{
end = reader.ReadToEnd();
reader.Close();
success = JsonConvert.DeserializeObject<bool>(end);
}
response.Close();
}
}
return success;
}
So now you have can POST JSON to an endpoint and receive a response the next step is to create the endpoint. The following code will get you started on an endpoint in mvc that will receive an application and process it.
[HttpPost]
public ActionResult SubmitApplication()
{
//Retrieve the POSTed payload
string body;
using (StreamReader reader = new StreamReader(Request.InputStream))
{
body = reader.ReadToEnd();
reader.Close();
}
var application = JsonConvert.Deserialize<Application>(body);
//Save the application
bool success = SaveApplication(application);
//Send the server a response of success or failure.
return Json(success);
}
The above code is a good start. Please note, I have not tested this code.
You have obviously more than one client for the data & operations. so a service is what you are looking for.
ASP.NET MVC is a good candidate for developing RESTful services. If you (and your Manager) are ready to use beta version, Then Checkout ASP.NET-Web API.
If you want to stay with a stable product, Go for MVC3. you may need to write some custom code to return the data in XML as well as JSON to server different kind of clients. There are some tutorials out there.
So create a Service (ASP.NET MVC / WCF Service) .You may then create 2 client apps, one for the external clients and another for the Internal users. Both of this apps can call methods in the Service to Create/ Read the user accounts / or whatever operation you want to do.
To make the apps more interactive and lively , you may conside including a wonderful thing called SiganalR, which helps you to get some real time data without continuosly polling the data base/ middle tier very in every n seconds !
I want to handle all server-side errors with jQuery on client side. For this purpose a create axception handling attrbute for my MVC3 application like this:
public class JsonErrorHandlerAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
filterContext.ExceptionHandled = true;
JavaScriptSerializer jsSerializer = new JavaScriptSerializer();
string result = jsSerializer.Serialize(new { error = filterContext.Exception.Message });
filterContext.HttpContext.Response.Write(result);
}
}
But with this approach it just returns normal json response with 200 OK result. A don't want to parse it on client side to determine if it has an error or not. So my question is what is the best way to throw an ajax error?
Add this to your function
HttpContext.Response.StatusCode = 500;
This will raise the error event if you use jQuery ajax, there you can react.
Here is the code for my base controller, the idea is that if the Authorization string is not in the HTTP Headers we kick them out. I swear it was working properly and now suddenly it does not work. Strangely when I debug it is actually stepping INTO the if statement so it is indeed true that the HTTP Header I am requesting is a NULL OR EMPTY string, HOWEVER, it is not exiting early and returning 403 Access Denied anymore... it was working fine and suddenly it is just ignoring the entire thing and eventually crashing later on in the app when I try to parse the Authorization String that WAS NOT ACTUALLY FOUND.
public class AuthController : Controller
{
protected int AccountID;
protected override void OnAuthorization(AuthorizationContext filterContext)
{
//if no authorization string is provided, access denied
if (string.IsNullOrEmpty(filterContext.HttpContext.Request.Headers["Authorization"]))
{
filterContext.Result = Content("Access Denied", "text/plain");
filterContext.HttpContext.Response.StatusCode = 403; //forbidden
base.OnAuthorization(filterContext);
}
//otherwise grab the authorization string and validate it
string authString = filterContext.HttpContext.Request.Headers["Authorization"];
string urlPath = string.IsNullOrEmpty(filterContext.HttpContext.Request.Path) ? "" : filterContext.HttpContext.Request.Path;
int getAccountID = 0;
//if authorization fails...
if (!AuthCore.Authorize(authString, urlPath, ref getAccountID))
{
filterContext.Result = Content("Access Denied", "text/plain");
filterContext.HttpContext.Response.StatusCode = 403; //forbidden
base.OnAuthorization(filterContext);
}
//AccountID will never be zero at this point
AccountID = getAccountID;
//carry on with Controller Action, request is valid and AccountID is known
base.OnAuthorization(filterContext);
}
UPDATE: Just tried filterContext.Result = new HttpUnauthorizedResult(); instead, same results. Controller action continues and throws error when trying to parse the header string that was not found.
UPDATE 2: Added "return;" after each of the base.OnAuthorization() calls besides the last one, now when it fails I get a 302 moved from MVC followed by a 404, which turns out is the app trying to redirect to a default login page URL that does not actually exist... could this be good enough? Maybe but I'd rather block it straight out rather than letting some wonky redirect happen as the way of blocking them, doesn't feel secure to me.
AH HA!
I was calling the base.OnAuthorization() too many times, apparently it's not actually a permanent goodbye from the thread... not sure why I thought it was now that I think about it... here is the working code:
protected override void OnAuthorization(AuthorizationContext filterContext)
{
int getAccountID = 0;
//if no authorization string is provided, access denied
if (string.IsNullOrEmpty(filterContext.HttpContext.Request.Headers["Authorization"]))
{
filterContext.Result = Content("Access Denied", "text/plain");
filterContext.HttpContext.Response.StatusCode = 403; //forbidden
}
else
{
//otherwise grab the authorization string and validate it
string authString = filterContext.HttpContext.Request.Headers["Authorization"];
string urlPath = string.IsNullOrEmpty(filterContext.HttpContext.Request.Path) ? "" : filterContext.HttpContext.Request.Path;
//if authorization fails...
if (!AuthCore.Authorize(authString, urlPath, ref getAccountID))
{
filterContext.Result = Content("Access Denied", "text/plain");
filterContext.HttpContext.Response.StatusCode = 403; //forbidden
}
}
//AccountID will never be zero at this point
AccountID = getAccountID;
//carry on with Controller Action, request is valid and AccountID is known
base.OnAuthorization(filterContext);
}
I think you should check out this post:
Securing your ASP.NET MVC 3 Application