The basic setup is this: I have an MVC application that starts up a console application based on user input. Suffice to say, at the end of the console application's code, I'm trying to make a web request to notify the system that the console application has finished execution. Now, when I'm debugging and running locally, I hit the web API method no problem.
However, when I publish the MVC application and copy it over to the server (in the respective wwwroot folder, it ceases to work.
The code for generating the request is relatively simple:
public void SendRequest(Uri uri)
{
using(var client = new WebClient())
{
// previously I was sending data, but this works locally regardless of the last parameter
// also, an example of a URI would be something like 'http://localhost:666/Ctrl/SomeFunction' though 'Ctrl' is replaced by the name of the controller
client.UploadValuesAsync(uri, "POST", new NameValueCollection());
}
}
Then the endpoint function is pretty barebones (for the sake of the question mostly):
public JsonResult SomeFunction()
{
// do stuff
}
I have logging code around the web request to see if it threw any exceptions, and other debugging code in the controller method as well. It doesn't throw any errors, doesn't run into any exceptions, and works fine locally. I'm not exactly sure what I'm missing.
As far as avoiding any SSL errors, it was suggested by a team member that I use
ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;. I know it's far from ideal, and should generally be avoided, but for now, it'll have to do.
UPDATE: I used UploadValues and checked the response. It comes back with some HTML that seems like an authentication redirect. So now the idea is to figure out how to exclude that route from authentication. So far the [AllowAnonymous] attribute on the controller hasn't been helpful (or messing around with the [Authorize] attributes in general). The suggestion I was given by a team member was to remove authorization for that controller action in the Startup.Auth.Cs file. I'm not sure if there's a better way for that or not. I might post a second question in regards to that.
at the end of the console application's code, I'm trying to make a web request
May be it's because local request is fast enough to be performed right before console application is closed, but not when it's published?
Try await client.UploadValuesTaskAsync(uri, "POST", new NameValueCollection()); or client.UploadValues(uri, "POST", new NameValueCollection()); It should not let console application shut down before request is over.
Related
History: I have a tiny app that has lived on a linux web server for a while: html5/javascript/perl cgi scripts. There is a sort of third party middle ware called Siteminder from CA that provides SSO services and it works fine. In my case on the linux box there is a dir in the DOCROOT that holds the Public facing html, js & perl cgi scripts. There is a different dir where the pages and scriots for the authorized content sits. Siteminder is configured to be aware of this auth-dir and the request paths that contain that auth-dir element.
Siteminder is tied into Apache and observes the request stream and when it sees a request with a path element that it cares about it holds the in-bound request; redirects the visitor to a branded auth page; deals with the auth flow and then, if authenticated, sends the original request on through. In this case the auth is tied to an AD group. Again, this works. My pages and code are totally unaware of the existence of Siteminder.
For reasons above my paygrade it has been decided to move the content from the linux box to an IIS server. Convert everything to C# .Net MVC. I am NOT a windows person but this is what is in my plate at the moment.
Our local Siteminder experts tell me that SM works exactly the same under IIS as linux. That once I convert my code that it doesn't need to be aware of SM either... yet something is not working.
In my case, due to user interaction a modal popup appears in the Public section (HomeController) that holds a small form. Clicking the submit button triggers a jQuery GET (I've also tried PUT, POST and a redirect) action to a method in the AuthController, a la:
$.get({
'url': "/Auth/AddNewData",
'contentType': "application/x-www-form-urlencoded; charset=UTF-8",
'dataType': "json",
'traditional': true,
'data': {
'thing': myThing,
'otherThing': myOtherThing
}
}).done(function(data, textStatus, jqXhr) {
console.log("it worked");
}).fail(function(jqXhr, textStatus, errorThrown) {
console.dir(jqXhr);
console.log(textStatus);
console.log(errorThrown);
});
I am aware that there are .Net ways of stating the target url, please bear with me.
What I expect to happen is that if the visitor does not have the auth session cookie that Siteminder sets then they should be redirected to the SM auth flow and once authorized have this request complete.
Instead, what happens is that:
I use the get method: it fires and I get a 302 "Object Moved" response.
if I use the post method: it fires and I get a 200 Ok response but the returned payload is a small amount of html from SM saying that if I am not redirected to my destination shortly to press the button included in the form in that html. The jQuery fail promis fires though because it is expecting a JSON result, not html.
if I use put nothing happens.
I comment out my jQuery ajax call and just use a "location" redirect then SM will put up its challenge page; I can log in; and, the triggering request will be "continued" into a loop of length 3: it calls the page and fails with a 302 that seems to send the request back to SM where it is sent back to the target address to get a 302 then back to Sm then back to the target but it generates a 404 message.
I am deep in the weeds here. Advice would be wonderful
Oh, PS: running this in debug mode on my desktop (no SM) works. Running the Release version on the IIS dev server with SM is what fails.
EDIT
More info: after some additional siteminder config I started getting CORS violation messages. I am setting CORS headers now but that changes nothing. Siteminder seems to strip the CORS headers :/
Another thing I have noticed is that if i craft the failing GET request as a javascript location.href=url + "?" + queryStringData redirect everything works. Current jquery is all but depreciating setting async to false so crafting a non-async version is more than I want to tackle at the moment.
The local siteminder folks will file a ticket soon I think.
EDIT 2
I have ended up with a hacky "fix". I can not use standard GET, POST, PUT, etc methods to interact with the MVC methods because Siteminder is in the way. I have added CORS headers and have tried JSONP, none of that works in this case.
I have to use "redirects" instead. Setting location.href = "/usr?thing=foo&bar=baz" in the javascript functions then redirecting to the url as a result of the MVC methods.
This might be a Siteminder config issue. The local Siteminder mavens have submitted a ticket.
Your question still isn't clear what the problem is with each of the bullets you listed. Is the GET behavior what you expect? A 302 is just a redirect, is it the redirect you expect?
For "POST", you are seeing the "post preservation" behavior. Its what SiteMinder does so that if your session has timed out in the middle of filling out a form, you don't lose your work. Post preservation is a configuration parameter in the "Agent Configuration Object" in SiteMinder. It sounds like your SM admins have configured the ACO differently for the IIS server than they did the Linux server.
PUT - nothing happens? You don't get any response at all, the connection just hangs?
Your last bullet, with the redirect loop, this looping typically indicates that your user is logged in (authenticated) but not authorized, which is a SiteMinder policy configuration issue (again it sounds like different policies are being applied to your IIS server than the Linux)
HTH!
-Richard
I have a POST IHttpActionResult method in my API controller that uses the [FromBody] attribute.
[Route("gameworld/generate")]
public IHttpActionResult PostNewWorld([FromBody] WorldData json)
Normally, when I want to test my controllers locally, I just goto the URL.
However, I can't do that with this method because I get this error:
The requested resource does not support http method 'GET'.
Is there a way for my local environment to see that this is a POST event?
Thanks!
First of all, ASP.NET Web Api is smart enough to deserialize your json into an object, so unless you really expect a string value in the body you can just put your type in there.
[Route("gameworld/generate")]
public IHttpActionResult PostNewWorld([FromBody] WorldData newWorld)
You can either test it manually with tools like Postman or Swagger, but manual tests are usually done once and then forgotten. This opens up for regression bugs where you make a change in the future, forget to retest the endpoint and break the application using the api.
Therefor, you should write unit tests to keep checking your code and prevent regression bugs. I've been using MyTested.WebApi on several projects and you can test both the routing and the actual calls. For example:
MyWebApi
.Server()
.Working()
.WithHttpRequestMessage(req => req
.WithRequestUri("api/bugs")
.WithMethod(HttpMethod.Post)
.WithContent(myJsonString)
.ShouldReturnHttpResponseMessage()
.WithStatusCode(HttpStatusCode.Created)
.WithResponseModelOfType<BugReport>()
.Passing(r => r != null);
There's a lot of things to be tested, so be sure to read the docs.
I have a following method in my controller:
[AcceptVerbs("GET", "OPTIONS", "HEAD")]
[OutputCache(Duration="3600" VaryByParam="None" VaryByHeader="Access-Control-Request-Headers;Origin")]
public new ActionResult Index()
{
//action body
}
It is handling both GET and OPTIONS (CORS) calls and so far there has been no problem. I've recently added the OutputCache attribute and started wondering if it's possible to cache a flawed OPTIONS response, by calling the GET. Namely, let's say a user with malicious intents calls my GET call with the CORS headers that I vary on. Is it possible that a user making the OPTIONS call with the same headers (this time used properly), will instead get the response from the previously cached GET, therefore nuking the whole OPTIONS call for the duration of the cache?
I was looking for an information, if the HTTP method is considered when creating an output cache entry, but just can't find it anywhere. I have tested this locally and it seemed that the GET and OPTIONS output could never get mixed up, no matter how hard I messed with the headers. Still, I would be much more relieved if I knew that what I described could really never happen.
My AngularJS $http post requests to my C# WebAPI restful service fail on Windows 8.1 in Internet Explorer 11. Firefox and Chrome both work.
Some more details:
The IT department says our network has no proxy
All 'automatically detect' and 'use proxy' settings are unchecked in all browsers
The requests fail to IIS both on my localhost and running the site and service on a local server
Enhanced protection mode of IE11 is off
The request's connection header is 'keep-alive' (I tried 'close' too and it still failed)
Sometimes one request will succeed and only from the second request will everything fail
No error is shown - the request in IE's network tab just says 'Pending' and all headers and body are blank
I'm using HTTP, not HTTPS
I've tried the meta tag 'X-UA-Compatible' IE9 and Edge
The requests fail for colleagues using IE11 on their machines too
All calls in all browsers work perfectly when Fiddler is running
Visual Studio 2013 browser link is turned off (so the SignalRArtery JS file isn't constantly making calls to the server and interfering with testing)
My AngularJS request call looks like this:
var url = UrlService.GetUrlOfApi() + 'Account/SignIn';
var postData = { 'username' : username, 'password' : password };
$http(
{
'url': url,
'data': postData,
'method': 'POST'
})
.success(function (data)
{
...
My C# service looks like this:
[RoutePrefix("Account")]
[AllowAnonymous]
public class AccountController : BaseController
{
[ResponseType(typeof(SecureResponseModel))]
[Route("SignIn")]
[HttpPost]
public IHttpActionResult SignIn(HttpRequestMessage request)
{
try
{
var userSignInDetails = GetPostData<AuthenticationRequestMessage>(request);
var token = _hisManager.AuthenticateUser(userSignInDetails.Username, userSignInDetails.Password);
return new SignInResponseMessage(token, ApiErrorCode.success, Request);
}
catch(APIException e)
{
throw;
}
}
This is what a failing call looks like in IE11, totally blank:
This is what a successful calls looks like when Fiddler is running:
Can anyone recommend any other settings to check or things to try please?
I have fixed this. My colleague advised the traditional debugging strategy of getting the simplest case to work - so I made a test post controller web service that worked every call:
I then saw the only difference between this method and the one that failed is the BaseController, which contained these methods:
I then changed the code to this to remove the suspicious looking async and await commands:
Everything now works perfectly. But can anyone explain why? In my googling this problem for the past day I've read about IE sending two packets instead of one like other browsers, and about resources being left open interfering with connections. But I don't understand how this await command broke the connection in just one browser.
I have a class that implements IHttpModule. This is a support class to help my application defend against DDOS attacks. After implementing the BeginRequest method, I tried to debug my code and for some reason, each time that I debug the class, I have multiple threads in Visual studio. I can't understand why, all of the sudden, while running this application on my local machine, I'm getting several threads, and it happens only in this class.
The HttpModule probably intercepts all requests to your application, including files (js, css, images, etc.)
Take a look at the Request object of each request, and look at the Url property to see what is happening.
Edit:
HttpModules are active very early in the request flow, and they will often get hit by most requests for the server, so keep the code in the HttpModule to a minimum. An example: if you're making permissions on files, make sure the request is actually hitting a file (ie. the requested url starts with /files/). Whenever possible, cache data for use in HttpModules, don't go to the database for each and every request in a HttpModule!
The reason why you probably get less hits in your actual application, is that even requests for images, js files, css files, etc. might make a hit in the HttpModule, but in your application, only requests meant for the application will hit your break points (aspx, asmx, etc. for Web Forms and recognized routes in ASP.NET MVC).
To get a look at what requests you're handling in a HttpModule, look at the value of the url variable:
void context_BeginRequest(object sender, EventArgs e) {
HttpApplication app = (HttpApplication)sender;
String url = app.Request.Url.OriginalString;
}