Running WebApi alongside MVC project in Azure - asp.net-mvc-4

I have a solution with an MVC project and also a separate Web Api project. I have been working on the the MVC portion and have had it hosted as a web role in a cloud service project.
Now I need to build on the Web Api. Running the solution as is in the azure emulator I'm unable to hit my Web Api controller, I get a 404 Not Found.
What steps do I need to take after creating the WebApi project in the solution in order to enable my MVC project alongside it to hit the Api controller using a jQuery ajax call (from the MVC project)?
Note: The portion of the application that will be consuming the Api is in a subdomain (ex "consumingapp.myapplication.com/api/Values". I don't know if that makes any difference.

Ok here are the steps to run MVC and WebApi side by side in Azure under a single web role:
Add only the MVC project as a Web Role in the Cloud Service project.
Open ServiceDefinition.csdef an configure as follows:
<Sites>
<Site name="Web" physicalDirectory="..\..\..\Application.Web">
<Bindings>
<Binding name="Endpoint1" endpointName="Endpoint1" />
</Bindings>
</Site>
<Site name="Web.Api" physicalDirectory="..\..\..\Application.Web.Api">
<Bindings>
<Binding name="Endpoint1" endpointName="Endpoint1" hostHeader="api.myapplication.com"/>
</Bindings>
</Site>
</Sites>
Note:
The physical directory is relative to the definition file that is deployed to CloudProject\bin\release so you need to back track 3 nodes to get to the solution folder. Also I had some trouble with this trying to run the project it would automatically switch the physicalDirectory back to a bad path. To fix that I right clicked the cloud project > Project Dependencies > make sure both projects are checked off. Also make sure to save and close all instances of the text editor for the definition file then Rebuild and finally Run. Seems like some kind of bug that was driving me nuts and eventually disappeared.
Configure your host files to allow for local testing using the emulator:
127.0.0.1 myapplication.com api.myapplication.com
To use this .NET cors implementation run the following Nuget command on your WebApi project:
Install-Package Thinktecture.IdentityModel
Add the following class (taken from the post) to your WebApi project:
public static class CorsConfig
{
public static void RegisterCors(HttpConfiguration httpConfiguration)
{
WebApiCorsConfiguration corsConfig = new WebApiCorsConfiguration();
corsConfig.RegisterGlobal(httpConfiguration);
corsConfig
.ForResources("Values") //Controller nae
.ForOrigins("http://myapplication.com", "myapplication.com:81")
.AllowAll();
}
}
Call RegisterCors() from Application_Start()
Make sure you Web.config in the WebApi project has OPTIONS verb for the ExtensionlessUrlHandler:
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
Make cross-origin request to hit your api controller:
$.ajax({ url: "http://api.myapplication.com/api/Values", ... })
And Viola!
Hope that helps others

Related

My Entity Framework Core API works fine locally, but fails with a 405 error in production

I have a .NetCore 3.1 API project that uses Entity Framework.
It is working perfectly when I run it locally from Visual Studio.
However, after publishing to a production IIS 8.5 server, I get the following errors when I try to hit an API that uses PUT on the production server.
xhr.js:178 PUT https://nationalparks.xyz.gov/api/plants/91 405 (Method
Not Allowed)
My controller begins like this:
[HttpPut("{id}")]
public async Task<IActionResult> PutPlant(long id, [FromBody] Plant plant)
{
...
}
And client-side looks like this:
await axios({
method: "PUT",
url: "api/plants/" + plant.id,
data: JSON.stringify(plant),
headers: { 'Content-Type': 'application/json; charset=utf-8' }
});
Honestly I'm stumped...I'm not sure why it's doing that.
I've seen a few posts saying to modify the web.config, but my app uses appsettings.json, not a web.config.
Any ideas?
Thanks!
The reason behind the issue is the WebDAV module intercepted the request. to resolve the issue you could follow the below workaround.
1)Remove WebDAV from your system:
open control panel-> “Turn Windows Features On or Off”->un-ticking the WebDAV publishing checkbox.
or
2)Add below code in your web.config file:
<system.webServer>
<modules>
<remove name="WebDAVModule" />
</modules>
<handlers>
<remove name="WebDAV" />
</handlers>
</system.webServer>
Please remember that after doing these changes you can nit use the WebDAV module in iis.
dotnet core applications do use web.config when running under IIS. You will notice that the publish command makes a web.config file that tells IIS which DLL to run for your application.
I think I had the same issue a while back. I fixed it by adding lines to web.config to remove the WebDAV modules. See this answer for more detail:
https://stackoverflow.com/a/12443578/65432

External http endpoint worker role, no acces right with executionContext elevated

Yet another post on http service on worker role.
Hello everyone,
I have been looking everywhere for an answer and I can't find any.
Here is the problem :
I have a worker role with a tcp entry point. It works fine locally and on azure. So far so good.
I have a windows phone app (sdk 8.0, .net 4.5) that I want to connect to this endpoint.
First problem here, the only way to access a wcf service with a windows phone project is to Right-click project, "Add service reference" and put the service address. BUT ! it doesn't work with tcp.net://{address}:{port}/{service name}.
I've searched and found that I need a http service.
All right then, I'll create a http endpoint. Code is easy, can be found everywhere.
Now here's the interesting part, I have the following error :
HTTP could not register URL http://+:8080/myservice. Your process does not have access rights to this namespace.
So I've looked it up on the internet and found 2 answers :
adding
<Runtime executionContext="elevated" />
to the ServiceDefinition.csdef file.
And setting
var binding = new BasicHttpBinding { HostNameComparisonMode = HostNameComparisonMode.Exact };
Now here's the kicker, I've done that and it still doesn't work.
Here are my Endpoints in ServiceDefinition.csdef file.
<Endpoints>
<InputEndpoint name="External" protocol="tcp" port="10100" />
<InputEndpoint name="Http" protocol="http" port="8080" />
</Endpoints>
Looking for help.

MVC4 Windows Authentication Redirect to Account/Login

I am setting up Windows Authentication in an MVC 4 application using Visual Studio 2013 and using the IIS Express Development Server. However, I get redirected to /Account/Login (as if I were using forms authentication).
I have no reference to WebMatrix in my bin folder (or anywhere) as described here: ASP.NET MVC3 and Windows Auth on IIS keeps redirecting to /Account/Login.
I have added these entries to appSettings in the web.config as suggested by this post:
MVC5 Redirects to Login.aspx when using Windows Authentication
<add key="autoFormsAuthentication" value="false" />
<add key="enableSimpleMembership" value="false"/>
Here is what I have done so far:
Added windows authentication to system.web.
<authentication mode="Windows"/>
Added the [Authorize] attribute to my controller. I have also tried using the authorization tag in the web.config instead of the attribute on the controller (deny users="?"). The results are the same.
For the Development Server settings in my project I changed these settings:
Anonymous Authentication = Disabled
Windows Authentication = Enabled
I can find no reference to FormsAuthentication. I can't figure out why it still redirects to a non-existent login page.
When the project was created it may have been done using a template that added Startup.Auth in the App_Start folder in your project. (The default template uses Individual User Accounts if you did not change it to windows authentication as the Authentication method in the create new ASP.Net Project dialog)
Try commenting out these lines if they are present
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
}
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
Or if you have not added anything to this file you could remove it completely and the call to it
ConfigureAuth(app);
found in the startup.cs in the root of the project
Now most of the account controller is no good to use if this case so be prepared to clean that up also.
This line is important and correct in the web config
<authentication mode="Windows"/>
these lines are probably not directly related to the issue and can be removed
<add key="autoFormsAuthentication" value="false" />
<add key="enableSimpleMembership" value="false"/>
The other development settings are also correct.

potentially dangerous Request servicestack

I am submitting a query string that contains a value
Body=%3Ch2%3E (Body=<h1>)
to a servicestack rest endpoint. That results in:
A potentially dangerous Request.QueryString value was detected from the client (Body=\"<h2>\").
I know that in MVC 4 you can allow Html content for an specific field, if you decorate the field in the model with [AllowHtml] like so:
[AllowHtml]
public string Body { get; set; }
Did that, but the error persists. Had doubts that it was service stack not partaking properly in the validation process, so tested by creating a pure MVC 4 controller with the same model, and that works fine.
However I need a solution for ServiceStack. Their documentation is thin and Google searches lead nowhere.
It looks like you are hosting your ServiceStack service inside an ASP.NET application.
You could add the following to the <system.web> section of your web.config file in order to disable request validation for the entire application:
<system.web>
<httpRuntime requestValidationMode="2.0" />
...
</system.web>
And if you want to disable request validation only for a particular endpoint and not the entire application use the <location> tag in your web.config:
<location path="hello">
<system.web>
<httpRuntime requestValidationMode="2.0" />
</system.web>
</location>
This will disable request validation for all /hello endpoints in your application. For example /hello?Body=%3Ch2%3E will work but /bar?Body=%3Ch2%3E won't work.
You can read more about request validation in ASP.NET in the following MSDN article.
And obviously you should not be worried about this if you are self-hosting your ServiceStack service.

Eliminate the .svc in the URL of a WCF 4 service using Routes?

I'm using WCF 4 on IIS 7.5 and want to eliminate the default .svc extension from the URL of all my RESTful services. I've seen the approaches documented using the Url Rewrite Module and an IHttpModule but I don't want to take those approaches.
I am vaguely familiar with the concept of Routes introduced in ASP.NET MVC and as I understand they are now abstracted out of MVC in Net 4 as System.Web.Routing. But in looking at the docs it appears I need to add a Global.asax file to my project which I'm not really keen on. Is there any other way to handle this?
I've also seen the Configuration-Based activation feature, but that only seems to eliminate the .svc file, but still requires I use .svc in the url of my service.
Can anyone summarize my options here for not needing .svc in my urls?
Sure, no problem: first off, read all about the new WCF 4 features in A Developer's Introduction to Windows Communication Foundation 4.
What you're looking for is called file-less service activation. It's a new setting in your <system.serviceModel> that looks something like this:
<serviceHostingEnvironment>
<serviceActivations>
<add factory="System.ServiceModel.Activation.ServiceHostFactory"
relativeAddress="[subfolder/]filename.svc" or "~/[subfolder/]filename.svc"
service="SomeNamespace.YourService"/>
</serviceActivations>
</serviceHostingEnvironment>
Basically, all the information you'd have in the *.svc file (path, service to call) is in this config section now.
You should be able to call this service at
http://yourserver/virtualdirectory/YourService
now - no more *.svc, no messy URL rewriting etc. - it just plain works!
Update: it doesn't seem to work that well, unless you go in and add a *.svc extension to your relative path - kind defeats the whole purpose!
If you want to register using an ASP.NET route, check out the MSDN docs on that topic. You'd have to have something like this in your application startup, in a web app that would be global.asax.cs:
void Application_Start(object sender, EventArgs e)
{
RegisterRoutes(RouteTable.Routes);
}
private void RegisterRoutes(RouteCollection routes)
{
routes.Add(new ServiceRoute("YourService",
new WebServiceHostFactory(), typeof(SomeNamespace.YourService)));
}
Hopefully, with that, you'll be able to get your service up and running without any *.svc file extensions!
Just to wrap up the answer and add one more point there. You'll need the same ASP.NET route registration as above:
void Application_Start(object sender, EventArgs e)
{
RegisterRoutes(RouteTable.Routes);
}
private void RegisterRoutes(RouteCollection routes)
{
routes.Add(new ServiceRoute("YourService",
new WebServiceHostFactory(), typeof(SomeNamespace.YourService)));
}
In order to get this working you need however to add some more things to web.config. The service hosting should be configured to be ASP.NET compatible. This can be done by adding aspNetCompatibiliyEnabled="true" to serviceHostingEnvironment element:
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true" />
Hope this clarifies and gives an easier to find solution.
Important clarification for IIS 7.5 and Framework 4.0:
For the Web routing module to work, it requires the application pool set to "Integrated Mode", it doesn't works in "Classic Mode"
One additional problem I've found after switching is that when in "Integrated Mode" the application crashed on startup because I had modules included in the <system.Web> section.
I fixed it by moving the modules to the <system.webServer> configuration section that is new for IIS 7