I want to build a SPA with AngularJS and ASP.NET Web API.
In regards to the frontend webpage I would like to limit the implication of asp.net as much as possible and move all the logic into Angular, the only thing the Web API will supply is a REST service.
I have created an index.html page with some angular that loads a basic list from the server.
But my index.html is accessed using ex. http://localhost:1234/app/index.html , what I would like now is to see my index.html from http://localhost:1234/ and also get a custom error page if I access some random link from this host.
Do I require ASP.NET to do this ? I would like to limit the use of ASP.NET as much as possible, only the basic required stuff.
And I am complete new to this.
Web.config :
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<handlers>
<clear />
<add
name="StaticFile"
path="*" verb="*"
modules="StaticFileModule,DefaultDocumentModule,DirectoryListingModule"
resourceType="Either"
requireAccess="Read" />
</handlers>
<staticContent>
<mimeMap fileExtension=".*" mimeType="application/octet-stream" />
</staticContent>
<defaultDocument enabled="true">
<files>
<clear/>
<add value="index.html"/>
</files>
</defaultDocument>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
Also added routing:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
Page error:
Server Error in '/' Application.
The resource cannot be found.
Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.
Requested URL: /
Well angular only does routing on client side, for your url needs you will still need to do some config on server side.
this should do the trick:
add this to web.config:
<system.webServer>
<defaultDocument>
<files>
<clear/>
<add value="(location of index.html)"/>
</files>
</defaultDocument>
As for errors (404 is among them), answer can be found here. That is only for when someone tries to get an url that does not exist, before angular has been loaded.
But once angular is loaded up, you do everything withing config, where you configure $routeProvider:
$routeProvider.when('/someUrl', {templateUrl: 'url/templatefile.html', controller: 'templateController'})
.when('/my404route', {templateUrl: 'url/my404file.html', controller: 'my404Controller'})
//when returns $routeprovider so you can chain "whens"
//finnaly add "otherwise"
.otherwise({redirectTo: '/my404route'});
//or just route to root with '/' if you won't handle unknown routes
By default visual studio deploy the site in a subfolder. To change it right click on your web project file / properties. Then in the Web tab specify the project url to be http://localhost:1234.
Related
I am trying to setup a .net core 2.2 web api to use a post verb. Anything other than a get verb returns a 405 no matter if it is run on my local machine (w10 iis eXPRESS 10.0) or the windows server (2016 R2 IIS 8.0). I've read the other posts about disabling WebDav in your config file, adding a route, and completely removing the WebDav feature. I have done all of those to no avail. I'm just starting to develop in core and find this baffling, on the same server is a non-core web api that runs on .net framework 4.5 that processes GET,PUT,POST,DELETE without error. And yes, I have restarted the server after making changes to any of the configurations. The following are the web.config changes that I made, the last one coming directly from MS. Basic project that reproduces the same error on my machine and server is here https://github.com/FranciscanMedia/error405_core/tree/master it is just a standard web api project you get when you fire up VS2019.
<system.webServer>
<handlers accessPolicy="Read, Script">
<remove name="WebDAV" />
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit"
path="*."
verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS"
modules="IsapiModule"
scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll"
preCondition="classicMode,runtimeVersionv4.0,bitness64"
responseBufferLimit="0" />
</handlers>
</system.webServer>
<system.webServer>
<modules>
<remove name="WebDAVModule" />
</modules>
<handlers>
<remove name="WebDAV" />
</handlers>
</system.webServer>
<system.webServer>
<validation validateIntegratedModeConfiguration="false"/>
<modules runAllManagedModulesForAllRequests="false">
<remove name="WebDAVModule"/>
</modules>
</system.webServer>
<system.webServer>
<handlers accessPolicy="Read, Script">
<remove name="WebDAV" />
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit"
path="*."
verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS"
modules="IsapiModule"
scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll"
preCondition="classicMode,runtimeVersionv4.0,bitness64"
responseBufferLimit="0" />
</handlers>
</system.webServer>
Short answer
It could be as simple as that. The reason is routing.
Just send your POST request to right URL like https://localhost:44327/api/values/123.
Detailed explanation
It's not the issue. It works as expected.
You make a GET request to https://localhost:44327/api/values/. It returns 200 OK.
But when you make a POST request to the same URL https://localhost:44327/api/values/. It says 405 Method not allowed.
However, you get 405. It is happening because you are hitting the GET endpoint with POST method.
Microsoft Docs says:
... the HTTP client sent a valid JSON request to the URL for a Web API application on a web server, but the server returned an HTTP 405 error message which indicates that the PUT method was not allowed for the URL. In contrast, if the request URI did not match a route for the Web API application, the server would return an HTTP 404 Not Found error.
https://learn.microsoft.com/en-us/aspnet/web-api/overview/testing-and-debugging/troubleshooting-http-405-errors-after-publishing-web-api-applications
If you simply remove the GET endpoint. The POST request will start returning 404 Not found. Which means that you are not hitting any registered route.
To send POST request you need to use different URL according to the routing rules.
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
// POST api/values
[HttpPost("{val}")]
public StatusCodeResult Post()
{
return Ok();
}
}
This attribute-based configuration means that route of your POST endpoint is /api/Values/{val}. Where {val} is any value. It's not processed in the endpoint.
If you want to process it, you should pass it to the method:
[HttpPost("{val}")]
public StatusCodeResult Post(string val)
{
return Ok();
}
I think that in your controller you have to import another library.
Try
using System.Web.Http;
Instead of
using Microsoft.AspNetCore.Mvc
Looking at what you have defined:
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
Then for the action:
[HttpPost("{val}")]
public StatusCodeResult Post()
{
return Ok();
}
Your routing matches the following url:
https://localhost:44327/api/values/StatusCodeResult
It is going to take your main route defined on your controller [Route("api/[controller]")]
Then you are defining the "template" to use "{val}"
This is telling it to use the ActionResult specific name and to expect var val to be passed/appened.
Checking out the official documentation here: https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/routing?view=aspnetcore-2.2
under section "Token replacement in route templates ([controller], [action], [area])"
They specifiy:
For convenience, attribute routes support token replacement by enclosing a token in square-braces ([, ]). The tokens [action], [area], and [controller] are replaced with the values of the action name, area name, and controller name from the action where the route is defined. In the following example, the actions match URL paths as described in the comments:
[Route("[controller]/[action]")]
public class ProductsController : Controller
{
[HttpGet] // Matches '/Products/List'
public IActionResult List() {
// ...
}
[HttpGet("{id}")] // Matches '/Products/Edit/{id}'
public IActionResult Edit(int id) {
// ...
}
}
If you want it to just route based on just verbs (follow a pattern where each api endpoint just handles operations for that specific object) then you would change your post method to just
[HttpPost]
public ActionResult Post(string val)
{
return Ok();
}
I totally agree with #Vladimir's answer. I dont have enough points to add comments to the answer by #vlaimir so i am adding my thoughts and suggestions.
The code you have on your github,
// POST api/values
[HttpPost("{val}")]
public StatusCodeResult Post()
{
return Ok();
}
This is a post and it would expect a value {val} per the route action configuration. Since you may try to hit the post without any value, thats not permitted. Ensure you supply some value and then do the POST. If you are using POSTMAN, you may have to supply the BODY of your request with some value. Swagger is a great util tool to embed into the web api's and that comes with excellent intuitive UI for our routes/resources. That might be even ideal to help determine and ensure you supply the right value.
Otherwise, you dont need to modify or worry about your IIS or IIS Express settings. or webdav.
I believe I have come across what I consider my most difficult task to do using crystal reports.
Problem
I am attempting to show to images on my report, one a varbinary stored in the database, and the second, a logo added from my desktop.The problem I am being faced with is, CrystalImageHandler not found and nothing I have tried works.
And the following errors are thrown
http://localhost:1979/ASP/CrystalImageHandler.aspx?dynamicimage=cr_tmp_image_9b453c74-dbe2-4f03-832e-b1bd43e6ec43.png 404 (Not Found)
http://localhost:1979/ASP/CrystalImageHandler.aspx?dynamicimage=cr_tmp_image_0bf1fda9-3e87-446d-94a4-aaad9aa7e53d.png 404 (Not Found)
What I have tried
I have attempted to ignore the routes. However, if I try to navigate to the image by removing the 'ASP' path where my aspx is, it still doesn't work. However, this is my RouteConfig.cs where the 'ASP' doesn't seem to be ignored
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.IgnoreRoute("{resource}.aspx/{*pathInfo}");
routes.IgnoreRoute("{*allaspx}", new { allaspx = #".*(CrystalImageHandler).*" });
routes.IgnoreRoute("ASP/{resource}.aspx/{*pathInfo}");
routes.IgnoreRoute("ASP/{resource}.aspx/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
I have also attempted to add it to the handler tag in the web.config file.
I have tried adding
<httpHandlers>
<add verb="GET" path="CrystalImageHandler.aspx" type="CrystalDecisions.Web.CrystalImageHandler, CrystalDecisions.Web,Version=13.0.2000.0, Culture=neutral, PublicKeyToken=692fbea5521e1304" />
</httpHandlers>
to the main web.config however, on launching my application I get the error An ASP.NET setting has been detected that does not apply in Integrated managed pipeline mode. it then says I can ignore the error If you are certain that it is OK to ignore this error, it can be disabled by setting system.webServer/validation#validateIntegratedModeConfiguration to false. But setting that to false does not work.
I place it in the second web.config file(the one in views folder., but that does not fix the issue of no picture being displayed.
I would greatly appreciate it if I am offered assistance or a bit of guidance to solve this issue. Cause it seems odd that something so simple could be this challenging.
I also faced this issue regarding loading images on crystal report in mvc but able to solve this issue by following these steps.
Possible Solutions:
The first thing to check is whether the Crystal Reports Image Handler has been included. This handler configuration doesn't seem to be added to the web.config by default, so open it up & look at the <httpHandlers> element. You need the following there:
<add verb="GET" path="CrystalImageHandler.aspx" type="CrystalDecisions.Web.CrystalImageHandler, CrystalDecisions.Web, Version=13.0.2000.0, Culture=neutral, PublicKeyToken=692fbea5521e1304"/>
Also, check the <handlers> element in the <system.webServer> parent node, as the handler needs to be added there as well:
<add name="CrystalImageHandler.aspx_GET" verb="GET" path="CrystalImageHandler.aspx" type="CrystalDecisions.Web.CrystalImageHandler, CrystalDecisions.Web, Version=13.0.2000.0, Culture=neutral, PublicKeyToken=692fbea5521e1304" preCondition="integratedMode"/>
Issue in ASP.NET MVC
If you are using Crystal Reports in ASP.NET MVC, the images may still fail to load. This is because the ASP.NET MVC routing engine is trying to map the resource request for the Image Handler to a controller action & since it can't, returns a 404 status.
To resolve this tell ASP.NET MVC routing engine to ignore requests for this resource. To do so, open up your routing configuration code (RouteConfig.cs).
There should already be an ignore for .axd resources. Add the following ignore rule:
routes.IgnoreRoute("{*allaspx}", new { allaspx = #".*(CrystalImageHandler).*" });
Source
I faced a similar issue. I found success in altering the path within the code shown below from Web.config. I replaced CrystalImageHandler.aspx with CrystalImageHandler*. This seems to have resolved my issue. I don't really understand why to be honest. I came someone's post online who suggested that he could'nt find the CrsytalImageHandler.aspx page and decided to point only to CrystalImageHandler. I thought this might be worth a try for some.
I was using VS2015, .Net 4.5, C#
<httpHandlers>
<add verb="GET" path="CrystalImageHandler*" type="CrystalDecisions.Web.CrystalImageHandler, CrystalDecisions.Web, Version=13.0.2000.0, Culture=neutral, PublicKeyToken=692fbea5521e1304"/>
</httpHandlers>
<handlers>
<add name="CrystalImageHandler.aspx_GET" verb="GET" path="CrystalImageHandler*" type="CrystalDecisions.Web.CrystalImageHandler, CrystalDecisions.Web, Version=13.0.2000.0, Culture=neutral, PublicKeyToken=692fbea5521e1304" preCondition="integratedMode"/>
</handlers>
Hope this helps,
Mark
Add to RegisterRoutes
routes.IgnoreRoute("{resource}.aspx/{*pathInfo}");
then fix CrystalImageHandler in Web.config
check web.config under <system.web> contains
(replace with crystal version)
<httpHandlers>
<add verb="GET" path="CrystalImageHandler*" type="CrystalDecisions.Web.CrystalImageHandler, CrystalDecisions.Web, Version=13.0.3500.0, Culture=neutral, PublicKeyToken=692fbea5521e1304" />
</httpHandlers>
and under <system.webServer> contains
<handlers>
<add name="CrystalImageHandler.aspx_GET" verb="GET" path="CrystalImageHandler*" type="CrystalDecisions.Web.CrystalImageHandler, CrystalDecisions.Web, Version=13.0.3500.0, Culture=neutral, PublicKeyToken=692fbea5521e1304" preCondition="integratedMode" />
</handlers>
Replace All
path="CrystalImageHandler.aspx"
with
path="CrystalImageHandler*"
After add necessary change in web.config. if still not work then you can try this
For ASP.NET MVC Project
in route config
add followoing line
routes.IgnoreRoute("Reports/Viewer/{resource}.aspx/{*pathInfo}");
you may need to change the path according to aspx page location
I forbid the access to Content, CSS, and JS files by disabling directory browsing. Now if i type url
https://xxxx:443/ceqr/Content/ I get the page in image below
What i want is to redirect user to https://xxxx:443/ceqr/ErrorPage/ if trying to access https://xxxx:443/ceqr/Content/
I have tried a few thing Like using Filter but since Content is not part of the Controller that does not work
Having location in web config does not either.
it does not get caught in Application_Error in golbal.ascx.cs.
I will appreciate your help
In your web.config file you could put this section.
<system.webServer>
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="403" />
<error statusCode="403" responseMode="ExecuteURL" path="/Error/PageForbidden" />
</httpErrors>
</system.webServer>
and you will create a Controller which has the name Error and the PageForbidden action like the following
public class ErrorController : Controller
{
public ActionResult PageForbidden()
{
Response.StatusCode = 403;
return View();
}
}
and also you should has a view with the name 'PageForbidden'
So IIS is handling that error, it hasn't got to the application yet. For this type of error, you'll want to configure HttpErrors in your web.config. For application level errors, use CustomErrors.
I have built a custom HttpHandler that issues a status page whenever a specific resource is requested by the load balancer.
Some more background: It can't be a controller as I need to be able to share it with other assemblies and the company coding policy is not to allow controllers from other assemblies.
Also, I cannot use a delegating handler as I don't want to affect the pipeline by adding a global message handler.
So I have the following in the web.config:
<system.web>
...
<httpHandlers>
<!-- Status Page-->
<add verb="GET" path="*" type="Web.Api.Framework.StatusPageHandler, Web.Api.Framework" />
</httpHandlers>
...
</system.web>
<system.webServer>
...
<handlers>
<clear/>
<add name="StatusPageHandler" path="*" verb="GET" type="Web.Api.Framework.StatusPageHandler, Web.Api.Framework" />
</handlers>
...
</system.webServer>
When I try to access the handler (http://foo.bar/status) it fails with a 404. If I remove the resource mapping for the default controller (from global.asax) then it works. i.e. without the following statement in global.asax it works:
routes.MapRoute("Default", "{controller}", null, null);
I stumbled upon a url for which it does work: http://foo.bar/status/XXX, but that is hardly ideal - we don't want to have to extend the url in that "ugly" way.
How do I get it to work?
One way to get it to work. Change Web.Config like so.
<add name="StatusPageHandler" path="status" verb="GET"
type="Web.Api.Framework.StatusPageHandler, Web.Api.Framework" />
Add the line in Global.asax (RouteConfig.cs?) to ignore this route. Make sure you add this line before routes.MapRoute.
routes.IgnoreRoute("status");
I am having quite a few problems with custom extensions and intercepting existing handlers.
What am I trying to do
Based upon persisted options, I would like all 'virtual' extensions to be handled by set handlers. All pages are dynamically built, and no actual files exist on the site. The site populates the content, forms the html output and returns it as the web result.
This is required as I am setting up a fat/thin relationship between 2 servers. The thin server will simply pass on the request to the fat server - where the request is processed and response issued back down the line.
The project is for a dynamic multi-domain content management system. The thin server may not be .net compatible (hence the external request), but will be .net optimised (hence the need for handlers).
The Problem
What I want is to re-route existing extensions - aspx; php; html.
I have achieved this in my local environment using a custom HttpModule which sets the appropriate handler. I have explored setting the tag in config, but the the extensions are re-routed using dynamic rules that are persisted.
As mentioned, this solution works on localhost.
When uploaded, the .Net extensions are handled by the module correctly but any custom extensions or non-.net extensions return a 404 error.
Seeking an alternative, I have experimented with routing within Global, but this dis not work either.
I have also attempted to use to register the custom extensions... but each are met with the same result - 404 not found.
Global Routing attempt:
public class Global : System.Web.HttpApplication
{
void Application_Start(object sender, EventArgs e)
{
RegisterRoutes(RouteTable.Routes);
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.Add(new Route("{action}.sqs", new SqlRequestHandler()));
}
.Config (for handler and module attempt)
<system.web>
<compilation debug="true" targetFramework="4.0" />
<httpRuntime requestValidationMode="2.0" />
<customErrors mode="Off"/>
<httpHandlers>
<add path="*.sqs" verb="*" type="CmsMapper.VirtualHandler, CmsMapper" />
<add path="*.sql" verb="*" type="CmsMapper.VirtualHandler, CmsMapper" />
</httpHandlers>
<httpModules>
<add name="SisBerCMS" type="CmsMapper.VirtualModule, CmsMapper" />
</httpModules>
</system.web>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
<modules>
<add name="SisBerCMS" type="CmsMapper.VirtualModule, CmsMapper" />
</modules>
<handlers>
<add path="*.sqs" verb="*" type="CmsMapper.VirtualHandler, CmsMapper" name="sqsHandler" />
<add path="*.sql" verb="*" type="CmsMapper.VirtualHandler, CmsMapper" name="sqlHandler" />
</handlers>
</system.webServer>
Custom Module (CmsMapper.VirtualModule)
if (extentionMap != null)
{
// note that extentionMap.ExtentionType is a predetermined enum
switch (extentionMap.ExtentionType)
{
// If the extention is banned then pass back a generic message
case ExtentionType.Banned:
this.WriteTextResponce("Invalid extention detected:" + extentionMap.Extention);
break;
// Remap .Ajax requests to the ajax handler
case ExtentionType.Ajax:
this._app.Context.RemapHandler(new AjaxHandler());
break;
// Remap session query or sql requests to the sql handler
case ExtentionType.SessionQuery:
this._app.Context.RemapHandler(new SqlRequestHandler());
break;
// if the extention is not ignored, re map to the virtual page handler
default:
bool isManagementServer = this._app.Context.Request.Url.Authority != VirtualModule.RESPONSE_SERVER;
bool isPostRequest = !String.IsNullOrEmpty(this._app.Context.Request.Form[HtmlRequest.RequestOrigin]);
bool isGetRequest = !String.IsNullOrEmpty(this._app.Context.Request.QueryString[HtmlRequest.RequestOrigin]);
bool isIgnored = extentionMap.ExtentionType == ExtentionType.Ignore;
if ((isPostRequest || isGetRequest) && !isIgnored)
{
this._app.Context.RemapHandler(new VirtualHandler());
}
else
{
this._app.Context.RemapHandler(new ExternalRequestHandler());
}
break;
}
}
All the handlers are pretty standard implementing the following:
public class SqlRequestHandler : IHttpHandler, IRequiresSessionState, IRouteHandler
Again, the preferred method - HttpModule - works on my localhost machine. This could be a server config issue (in which case I'm looking for a work around), but the fact that the .net extensions are being handled is strange - as this would imply that issues with medium trust should not apply, however issues regarding extension handling on the server may take priority over the .net application.
The server is shared hosting (therefore I am unable to alter the machine.config files), is IIS6 using 4.0.
Thank you for any suggestions on how to resolve this issue.
Mike
You need to configure web site in IIS 6.0 to route all extensions (including extensionless paths known as wildcard extension mapping) to ASP.NET ISAPI dll (and disable the check for file exists).
You can of course do this mapping selectively only for those extensions that you want to route via ASP.NET code. But wildcard mapping will be more useful in case you don't have predefined set of extensions.
In the absence of such mappings, IIS will not forward requests for unknown extensions to ASP.NET (and routing code will not even come into picture) - rather IIS will pass the extension to default (static file) handler that will issue 404 if file is not present.
See this article that describes these steps (for ASP.NET MVC but the same applies to your case): http://haacked.com/archive/2008/11/26/asp.net-mvc-on-iis-6-walkthrough.aspx
Near the end of article, author has given how to add wildcard script map