Hosting an MVC6 application under default website - c#

I have hosted many ASP.NET and MVC applications before. I was playing with MVC6 lately and tried to host an MVC6 application.
Everything works fine if I host it as a new website. When I host it as an application under the default website of IIS, it only shows an empty page. Please find the log information below
warn:
Microsoft.Extensions.DependencyInjection.DataProtectionServices[0]
Neither user profile nor HKLM registry available. Using an ephemeral key repository. Protected data will be unavailable when
application exits. warn:
Microsoft.AspNet.DataProtection.Repositories.EphemeralXmlRepository[0]
Using an in-memory repository. Keys will not be persisted to storage. Hosting environment: Production Now listening on:
http://localhost:23000 Application started. Press Ctrl+C to shut down.
info: Microsoft.AspNet.Hosting.Internal.HostingEngine[1]
Request starting HTTP/1.1 GET http://localhost/MVC6 info: Microsoft.AspNet.Hosting.Internal.HostingEngine[2]
Request finished in 0.0687ms 404
Note: Default website uses application pool asp.net4.5 and my MVC6 application uses it's own application pool as mentioned in http://docs.asp.net/en/latest/publishing/iis.html#iis-server-configuration
Anyone else faced similar problem like this? I want to know how to make it work under default website

Edit: This is a bug in vs2015 rc1 https://github.com/aspnet/Hosting/issues/416#issuecomment-149046552.
There is a workaround for this bug in above link but I followed a different method because I need to host my application in more than one website without republishing.
I resolved the above problem using the Route attribute. After adding the route attribute to an action result, application works fine
public class HomeController : Controller
{
[Route("MVC6")]
[Route("")]
public IActionResult Index()
{
return View();
}
}

Related

Kentico v8.2.12: Why is my WebAPI Route not registered correctly (usually only on the first release)?

Summary
A Kentico 8.2 website fo which I have recently implemented a Web API service isn't registering routes on first deployment and all calls return 404. Further redeployments usually fix the issue, but I would like to fix it permanently before it is released to PROD.
What is preventing the first deployment from registering the route properly?
Background
We have a Kentico v8.2.12 website that uses Web Forms using .NET Framework v4. I have registered a Web API Controller, but it appears on the first release the route isn't registered and any calls to the service returns "404 (Not Found)".
When I first deployed to the DEV environment the Web API route wasn't registered, but upon deploying another build it magically worked. One or two other releases into the DEV environment caused similar issues, but in these instances re-deploying the same build worked.
The same issue has now occurred when released to UAT, however as the deployments are carried out by another team it will be more time-consuming to re-deploy builds and looks unprofessional. I am also wary of this occurring in PROD---which may cause the live website to be down further than necessary.
Web API Implementation
The Web API Controller is inside the CMS Website project and not a separate library.
Global.asax.cs
The Global.asax.cs file's Application_Start() method registers the route and looks similar to the below:
protected void Application_Start()
{
// Scripts Bundling here, which havs been removed for brevity
BundleTable.EnableOptimizations = false;
// Registering the API
RouteTable.Routes.MapHttpRoute(
name: "DefaultApiWithAction",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new {id = RouteParameter.Optional}
);
}
MyController.cs
My Controller looks similar to the below stored under the CMS website: CMSApp/ApiControllers/MyController.cs
[assembly: RegisterApiController(typeof(CMSApp.ApiControllers.MyController))]
namespace CMSApp.ApiControllers
{
public class MyController : ApiController
{
Channel Channel = new Channel();
[HttpPost]
public int Create()
{
Response objResponse = Channel.Instance.DoSomething();
HandleResponse(objResponse);
return objResponse.SessionHandle;
}
}
}
In the webbrowser, accessing /api/my/create returns a 404 (Not Found), but I expect it to tell me it's a POST method.
Lib versions [Edit, I have since updated the libs but issue still prevails]
Microsoft.AspNet.WebApi : v4.0.30506
Microsoft.AspNet.WebApi.Client : v4.0.30506
Microsoft.AspNet.WebApi.Core : v4.0.30506
Microsoft.AspNet.WebApi.WebHost : v4.0.30506
Question?
Why do the first deployments into an environment not work, but most further deployments work as I expect them to?
The issue was due to ASP.NET caching.
Once "MS-ApiControllerTypeCache.xml" was removed under "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files" and IIS was restarted, the controller was picked up.

Unable To Post Webhook To C# Application On Azure

I am working on an email program for a WordPress WooCommerce store. I have added a webhook into the WooCommerce settings in order to hit a C# WebAPI application that I have created. I am trying to get run an email process every time an order is created.
I created an API controller with that accepts the JSON data that is sent over from WooCommerce, and when testing it locally from a Postman request, the controller is hit no problem.
I am trying to publish the application on Azure, and when I do, I am getting a 400 error from both the WooCommerce settings as well as any Postman requests.
I have tried setting
<system.webServer>
<httpErrors existingResponse="PassThrough"/>
</system.webServer>
in the web.config file, which then returned a 502 error from Postman, but still the same error on the WooCommerce webhook side.
I also tried re-deploying which did not work either.
I am able to view the homepage as well as the API controller link on the standard MVC homepage/menu view.
The controller is a standard API controller inheriting from the APIController class:
public class OrdersController : ApiController
and it contains one method, ProcessOrders, with an [HttpGet, HttpPost] attribute on it, and a route of /api/orders/callback.
The controller is responsible for inserting the payload from the webhook into the database and then it uses some other classes email out some specific information about the product.
Is there some kind of setting that needs to be set in the Azure portal or on the web.config file? I am not very experienced with Azure so I am not too familiar if there is anything else that needs to be done for this.
Azure Information
I am deploying to azure from quick publish inside Visual Studio
A Pay-As-You-Go resource group
.Net Framework version 4.7
Remote debugging enabled
Web App app service
The only App service setting is WEBSITE_NODE_DEFAULT_VERSION set to 6.9.1
I have tried both Release and Debug configurations, the connection is valid when trying the Validate Connection option inside configuration, the File Publish Options are all unchecked (Remove additional files at destination, precompile during publishing, exclude files from app_data folder) and the publish works fine, and the app is accessible, except for the api controller.
The project is built as a .Net framework version 4.6.1 with Web API.
Thanks in advance for any help!
Edit
I have removed the parameter that was part of the original method that is being hit by the API, and I am now getting the error of No HTTP resource was found that matches the request URI. I have tried changing the Route data annotation as well as just making it HttpGet to see if it was accessible, and it is not working. I created a second action on the controller just to test returning a string, and that worked without problem, so I am not sure why it is not accessible. The intro to the method is as follows:
[HttpGet]
[Route("api/orders/callback")]
public string Callback() { return "Test"; }
I also updated this method to try just returning a simple string and it does not work. I also adjusted the second test method to accept a string POSTed to it and it is returning The requested resource does not support http method 'POST'.
This method looks like the following:
[HttpPost]
[Route("api/orders/new")]
public string SecondCallback(string payload) {
return payload;
}

asp.net core 2.0 deployment - InvalidOperationException: The antiforgery token could not be decrypted

Recently I developed a asp.net core 2.0 web app in my company and in debug mode works perfect, however when I deployed in our testing server into IIS and we try to execute from a client machine it ran into a problem:
An unhandled exception occurred while processing the request.
CryptographicException: The key {0851ad3b-df33-4cf7-8c3a-5c637adaa713} was not found in the key ring.
Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.UnprotectCore(Byte[] protectedData, bool allowOperationsOnRevokedKeys, out UnprotectStatus status)
InvalidOperationException: The antiforgery token could not be decrypted.
Microsoft.AspNetCore.Antiforgery.Internal.DefaultAntiforgeryTokenSerializer.Deserialize(string serializedToken)
The problem starts when I submmit login page. I investigated links with same problems here and other blogs, but I found that has to be with ValidateAntiForgeryToken and solution is related with Microsoft.AspNetCore.DataProtection. I added nuget package Microsoft.AspNetCore.DataProtection.Redis to my project and I added in ConfigureServices of startup class following code:
var redis = ConnectionMultiplexer.Connect("192.168.10.151:80");
services.AddDataProtection().PersistKeysToRedis(redis, "DataProtection-Keys");
services.AddOptions();
Our testing server ip is 192.168.10.151, however app throws following exception:
RedisConnectionException: It was not possible to connect to the redis server(s); to create a disconnected multiplexer, disable AbortOnConnectFail. InternalFailure on PING
¿Why it doesn't connect since is resolving in the same web app server?
¿Where is DataProtection-Keys database located?
as a workaround, I changed method by using PersistKeysToFileSystem as follows:
services.AddDataProtection()
.SetApplicationName("myapp-portal")
.PersistKeysToFileSystem(new System.IO.DirectoryInfo (#"c:\ProgramData\dpkeys"));
However running app in test server 192.168.10.151, when login form is submitted, goes back to login page. Checking stdout log file, only shows:
Hosting environment: Production
Content root path: C:\inetpub\wwwroot\OmniPays
Now listening on: http://localhost:30064
Application started. Press Ctrl+C to shut down.
Checking network messages by chrome's developers tools I noticed something:
Request URL: http://192.168.10.151/OmniPays/Account/Login
Request Method: POST
Status Code: 302 Found
Remote Address: 192.168.10.151:80
Referrer Policy: no-referrer-when-downgrade
and then ...
Request URL: http://192.168.10.151/OmniPays/Home/Main
Request Method: GET
Status Code: 302 Found
Remote Address: 192.168.10.151:80
Referrer Policy: no-referrer-when-downgrade
AccountController's Login action redirect request to HomeController's Main action only if authentication succeded, and Main action has [Authorize] attribute. For some reasons I can't achieve understand, Main action fails and return to Login page. URL in chrome shows: http://192.168.10.151/OmniPays/Account/Login?ReturnUrl=%2FOmniPays%2FHome%2FMain
I'm using Microsoft Identity. In debug mode works fine and if I deploy app in my local PC on IIS also works fine. ¿Maybe any SDK is missing in the server?
Please need help!!
Solution was found! the cause of problem was not in IIS neither the Server, connection to the server is using http rather than https, no certifies involved to validate secure connection, however testing in differents servers app works ok, so I felt really disappointed. Solution was to remove cookies an any data related with this URL pointing to Development Server (failing) in all browsers, data that was previously stored, and voila!!, now app works perfect. By default, as bhmahler comments data protection is made in memory and I left configuration by default, I mean, not explicitly persistence in redis nor PersistKeysToFileSystem and works fine, however is important to set DataProtection to strong data sensitive protection.
I'm newbie about these topics and It's unbelievable such a simple thing caused on me that waste of time. Thanks to all!.

ASP.Net Core Web API, deployed under IIS is returning 404

I have a new Web API developed in ASP.NET Core. This Web API is supposed to be deployed in IIS and will have to work over SSL, so I have the [HttpsRequired] attribute on all my controllers. I struggle to make it work while deployed, so for now I relaxed the requirements and commented out those attributes. Doing so, I was able to create two bindings in IIS, one for HTTPS and one for HTTP. Given that my Web API is created in ASP.NET Core, I followed the deployment steps Rick Strahl has in his excellent blog post. I have selected "No Managed Code" for the .NET CLR version. The IIS machine is a 64-bit Windows Server 2012 R2 environment - not sure whether this matters or not. The .NET Core Windows Server Hosting bundle has been installed on the server and I can see the AspNetCoreModule listed in the Modules grid.
If i try to access the Web Api (I created a very simple GET method that returns some information regarding the assembly) with Fiddler, I get a 404 error. For now, i run Fiddler on the same machine, so I tried all combinations (localhost, IP address and full machine name in the domain).
No errors are logged in the EventViewer. Does anyone have any suggestion on how to troubleshoot this issue?
TIA,
Eddie
EDIT1: Here is my controller:
[Route("api/info")]
//[RequireHttps]
public class InfoController : Controller
{
private ITncRepository _repository;
public static ApplicationAssemblyDetails ApplicationAssemblyDetails { get; set; }
public InfoController(ITncRepository repository)
{
_repository = repository;
ApplicationAssemblyDetails = ApplicationAssemblyDetails.Current;
}
[HttpGet("")]
public JsonResult Get()
{
return Json(new WebApiInfoModel()
{
CurrentTime = DateTime.Now,
CurrentUtcTime = DateTime.UtcNow,
AssemblyName = ApplicationAssemblyDetails.ApplicationAssembly.FullName,
VersionNumber = ApplicationAssemblyDetails.VersionNumber,
BinFolder = ApplicationAssemblyDetails.BinFolder,
BuildMode = ApplicationAssemblyDetails.BuildMode,
TradeMark = #" © 2016-2017 * SomeCompany (www.somecompany.com)"
});
}
}
The ApplicationAssemblyDetails is a nuget package that gives some info about the current assembly. WebApiInfoModel is my model class for the Web API Information I want to pass back as a test to the client.
The web.config file:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
</handlers>
<aspNetCore processPath=".\My_ASP_NET_Core_Web_API.exe" arguments="" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="true" />
</system.webServer>
</configuration>
Finally, to answer your last question, Ignas, I use a Publishing Profile that uses the File system as a method, targets the .NET Framework 4.5.2, using the release configuration. Given that my project is a Web API and not an MVC 6 Web Application, the publishing package creates a stand-alone application. Since the clients need to call my Web API using SSL, I think that it has to be hosted in IIS, so running the standalone application would not work. Of course, for testing purposes, I could try to run it. That's why I commented out the [HttpsRequired] attribute. I will try that and report back, but for now I hope I gave you all the information you required.
I'm having a setup very close to yours (Asp.Net core, Web API, IIS, HTTPS ...) working fine on my end.
I faced the same issue at some point because I was not using the proper path to access my controller/action, it depends on how you deployed it under IIS. For instance, in my case when I use Kestrel directly it goes through a URL like that:
http:// localhost:5000/controllerName/actionName
But I can also contact my Web API via IIS and in that case I need to use a URL like that:
http:// localhost:5001/applicationName/controllerName/actionName
Have you created an application under IIS that could explain you getting a 404 because you would not use the proper path?
For instance, in my case:
screenshot of the asp.net core api under iis
And I'm accessing it, through the URL:
https: //servername:serverport/RequestPortalAPI/ControllerName/ActionName
In the end, it was a matter of properly configuring Widows Authentication. For Fredrik and anyone else reading this post for a solution, these are the steps I performed:
In IIS, in the Authentication form for my Web API, I disabled Anonymous Authentication and I enabled Windows Authentication:
Make sure that "Negotiate" is at the top of the list for Enabled Providers:
In the Application Pools, I configured my Web API to run under an account that the UIT department of my client has given me:
The configuration file of my Web API (web.config) contains the following settings:
Now we are getting into the dark areas of the problem. In order to use Windows Authentication and let the credentials of the caller be passed through to the backend (in my case a SQL Server database), the Web API has to be configured to use Kerberos. I found this after I opened a ticket with Microsoft and I worked closely with one of their engineers. For this to happen, you need to follow these steps:
Create a Service Principal Name (SPN) for your Web API and the domain account it runs under. You need to run this command:
Where hostname is the fully qualified domain name of your Web API. The Domain\Username are the domain account under which the Web API is running. You need special domain privileges, so you may want to involve someone from IT. Also, from now on, you need to access your Web API by the full domain name, not by IP address. IP address won't work with Kerberos.
Also, with the help of your IT person, you need to enable delegation for any service using Kerberos for the domain account under which you run your Web API. In the Active Directory Users and Computers, locate the account you use to run your Web API, bring up its properties, click on the Delegation tab and enable the second option "Trust this user for delegation to any service (Kerberos Only):
We have also made some changes on the server that runs our database, but I am not 100% those are truly required, so I won't add them here because I don't even know if you use SQL Server or some other backend repository.
Let me know if you need those as well and I will add them later.
Good luck,
Eddie

DNN Web API Server Error

I'm repeatedly getting an Internal Server Error 500 when trying to make a simple call to a DNN Web API controller. I do not get this error on my development machine, nor do I get it on one of our deployment servers. However, one of our other deployment servers is the problem; and I'd like to figure out why.
Consider the following, simplistic API controller in TheBestController.cs
namespace MyTestLibrary.Controllers
{
public class TheBestController : DnnApiController
{
[DnnAuthorize]
[HttpPost]
public HttpResponseMessage TestMe()
{
return Request.CreateResponse(HttpStatusCode.OK, "I'm working");
}
}
}
With this RouteMapper in RouteMapper.cs
using DotNetNuke.Web.Api;
namespace MyTestLibrary
{
public class RouteMapper : IServiceRouteMapper
{
public void RegisterRoutes(IMapRoute mapRouteManager)
{
mapRouteManager.MapHttpRoute("TheBestController", "default", "{controller}/{action}", new[] { "MyTestLibrary.Controllers" });
}
}
}
With the following AJAX call from my Javascript:
$.post("DesktopModules/MyTestLibrary/API/TheBest/TestMe", function(data) {
alert(data);
});
I have made sure that all of the correct permissions are set for the DNN application in IIS (as well as mirrored those and all other pertinent settings that are on our server that has this working). I place the compiled MyTestLibrary.dll in the bin folder of the DNN site, and I place the javascript file in the Resources/Shared/scripts folder of the DNN site. The DNN site is reading the javascript with no issues, and I am not using a module (and would not like to because I want all of my code to be easily transferrable to an MVC site).
I have also tried using the [AllowAnonymous] tag on the controller method (to no avail).
The version of DNN on all machines is 07.01.01, and the two servers are running Server 2008 R2 64bit. The dev machine is running Win 7 64 bit.
Any ideas?
To break the comments out into an answer ;)
I've seen where IIS on Windows Server 2008 can somehow corrupt a folder that a DNN website is using, and that starts to cause issues with certain web services in DNN. Two solutions that I know have worked in the past for me.
1) Setup a new site in IIS and install DNN in that folder.
or
2) Move the DNN files to a different folder on the server, point the existing IIS website to that folder, instead of the original one.
One of those two should hopefully work for most people that run into this problem.
Now, what exactly goes wrong in IIS and why can the existing folder be fix? No clue :(

Categories