Servicestack Display 404 page CatchAllHandlers - servicestack

Im using servicestack Core with kestrel. I made a CatchAllHandlers delegate with the following code.
var requestType = typeof(NotFoundPage);
var restPath = new RestPath(requestType, pathInfo);
return new RestHandler { RestPath = restPath, RequestName = restPath.RequestType.GetOperationName(), ResponseContentType = contentType };
But the problem is that my ServicestackApi now is no longer reachable, url: /json/reply/GetApiCall goes to the 404 not found page.
Is there a way to solve this? can i check if its an api call or can i go later in the pipeline to handle the request?
update
I found that if i remove CatchAllHandler and just add the next middleware this middleware is called:
app.Use((context, next) =>
{
context.Response.Body.Write("yaayaya");
return Task.CompletedTask;
});
But this is not what i want, i want to stay inside the servicestack request.
update 2
Looking at the source-code i find HttpHandlerFactory has a property NotFoundHttpHandler Which is filled from the AppHost.
CustomErrorHttpHandlers.Add(HttpStatusCode.NotFound, new PageNotFoundHandler());
The only downside is that i can't provide any request specific information to this Urlhandler, such as the url itself:
public class PageNotFoundHandler : RestHandler
{
public PageNotFoundHandler()
{
var restPath = new RestPath(typeof(Error404), "/Url/For?");
}
}
Trying to make this work but i'm getting stuck on that my RestHandler has different amount of components than the url since this PageNotFoundHandler is made before the RestHandler.
But Basically what im looking for is to Handle a different service/InputDto
I've tried RequestConverters but this code is not reached when CatchAllHandlers doesn't return an Handler. so im stuck in this space in the middle. Anyway i could make all the left over routes, route to a single Dto?

.NET Core's new pipeline programming model expects you to call the next middleware if it wasn't already handled by any of the previously registered middleware which is how .NET Core lets you combine multiple different middlewares into the same App.
Handling Not Found Requests with the last Middleware
The last middleware that's registered will be able to handle any unhandled requests so for instance if you wanted to return a static image for unhandled requests you could register middleware after ServiceStack, e.g:
app.UseServiceStack(new AppHost());
app.Use(new StaticFileHandler("wwwroot/img/404.png"));
Or if you wanted to return a custom 404 page instead:
app.Use(new RazorHandler("/404"));
Which will render the /wwwroot/404.cshtml Razor View with ServiceStack's MVC Razor Views.
This would be the preferred way to handle Not Found requests in .NET Core in which you will be able to register additional middleware after ServiceStack to handle non-ServiceStack requests.
Calling a ServiceStack Service for unhandled requests
If you wanted to call a ServiceStack Service for any unhandled requests you can use a Fallback Route which matches on any request, e.g:
[FallbackRoute("/{Path*}")]
public class Error404
{
public string Path { get; set; }
}
public class UnhandledRequestService : Service
{
public object Any(Error404 request) => ...;
}

Related

Validation Error: Using global entity manager instance methods for context specific actions is disallowed

Using MikroORM and getting this error:
ValidationError: Using global EntityManager instance methods for context specific actions is disallowed.
If you need to work with the global instance's identity map, use `allowGlobalContext` configuration option or `fork()` instead
The code that it corresponds to is below:
import { MikroORM } from "#mikro-orm/core";
import { __prod__ } from "./constants";
import { Post } from "./entities/Post";
import mikroConfig from "./mikro-orm.config";
const main = async () => {
const orm = await MikroORM.init(mikroConfig);
const post = orm.em.create(Post, {
title: "my first post",
});
await orm.em.persistAndFlush(post);
await orm.em.nativeInsert(Post, { title: "my first post 2" });
};
main().catch((error) => {
console.error(error);
});
I am unsure where I need to use the .fork() method
Don't disable validations without understanding them!
I can't believe what I see in the replies here. For anybody coming here, please don't disable the validation (either via MIKRO_ORM_ALLOW_GLOBAL_CONTEXT env var or via allowGlobalContext configuration). Disabling the validation is fine only under very specific circumstances, mainly in unit tests.
In case you don't know me, I am the one behind MikroORM, as well as the one who added this validation - for a very good reason, so please don't just disable that, it means you have a problem to solve, not that you should add one line to your configuration to shut it up.
This validation was added to MikroORM v5 (so not typeorm, please dont confuse those two), and it means exactly what it says - you are trying to work with the global context, while you should be working with request specific one. Consult the docs for why you need request context here: https://mikro-orm.io/docs/identity-map#why-is-request-context-needed. In general using single (global) context will result in instable API response and basically a one huge memory leak.
So now we should understand why the validation is there and why we should not disable it. Next how to get around it properly.
As others mentined (and as the validation error message mentioned too), we can create fork and use that instead:
const fork = orm.em.fork();
const res = await fork.find(...);
But that would be quite tedious, in real world apps, we usually have middlewares we can use to do this for us automatically. That is where the RequestContext helper comes into play. It uses the AsyncLocalStorage under the hood and is natively supported in the ORM.
Following text is mostly an extraction of the MikroORM docs.
How does RequestContext helper work?
Internally all EntityManager methods that work with the Identity Map (e.g. em.find() or em.getReference()) first call em.getContext() to access the contextual fork. This method will first check if we are running inside RequestContext handler and prefer the EntityManager fork from it.
// we call em.find() on the global EM instance
const res = await orm.em.find(Book, {});
// but under the hood this resolves to
const res = await orm.em.getContext().find(Book, {});
// which then resolves to
const res = await RequestContext.getEntityManager().find(Book, {});
The RequestContext.getEntityManager() method then checks AsyncLocalStorage static instance we use for creating new EM forks in the RequestContext.create() method.
The AsyncLocalStorage class from Node.js core is the magician here. It allows us to track the context throughout the async calls. It allows us to decouple the EntityManager fork creation (usually in a middleware as shown in previous section) from its usage through the global EntityManager instance.
Using RequestContext helper via middleware
If we use dependency injection container like inversify or the one in nestjs framework, it can be hard to achieve this, because we usually want to access our repositories via DI container, but it will always provide we with the same instance, rather than new one for each request.
To solve this, we can use RequestContext helper, that will use node's AsyncLocalStorage in the background to isolate the request context. MikroORM will always use request specific (forked) entity manager if available, so all we need to do is to create new request context preferably as a middleware:
app.use((req, res, next) => {
RequestContext.create(orm.em, next);
});
We should register this middleware as the last one just before request handlers and before any of our custom middleware that is using the ORM. There might be issues when we register it before request processing middleware like queryParser or bodyParser, so definitely register the context after them.
Later on we can then access the request scoped EntityManager via RequestContext.getEntityManager(). This method is used under the hood automatically, so we should not need it.
RequestContext.getEntityManager() will return undefined if the context was not started yet.
Simple usage without the helper
Now your example code from the OP is very basic, for that forking seems like the easiest thing to do, as its very bare bones, you dont have any web server there, so no middlewares:
const orm = await MikroORM.init(mikroConfig);
const emFork = orm.em.fork(); // <-- create the fork
const post = emFork.create(Post, { // <-- use the fork instead of global `orm.em`
title: "my first post",
});
await emFork.persistAndFlush(post); // <-- use the fork instead of global
await orm.em.nativeInsert(Post, { title: "my first post 2" }); // <-- this line could work with the global EM too, why? because `nativeInsert` is not touching the identity map = the context
But we can use the RequestContext here too, to demonstrate how it works:
const orm = await MikroORM.init(mikroConfig);
// run things in the `RequestContext` handler
await RequestContext.createAsync(orm.em, async () => {
// inside this handler the `orm.em` will actually use the contextual fork, created via `RequestContext.createAsync()`
const post = orm.em.create(Post, {
title: "my first post",
});
await orm.em.persistAndFlush(post);
await orm.em.nativeInsert(Post, { title: "my first post 2" });
});
The #UseRequestContext() decorator
Middlewares are executed only for regular HTTP request handlers, what if we need
a request scoped method outside that? One example of that is queue handlers or
scheduled tasks (e.g. CRON jobs).
We can use the #UseRequestContext() decorator. It requires us to first inject the
MikroORM instance to current context, it will be then used to create the context
for us. Under the hood, the decorator will register new request context for our
method and execute it inside the context.
This decorator will wrap the underlying method in RequestContext.createAsync() call. Every call to such method will create new context (new EntityManager fork) which will be used inside.
#UseRequestContext() should be used only on the top level methods. It should not be nested - a method decorated with it should not call another method that is also decorated with it.
#Injectable()
export class MyService {
constructor(private readonly orm: MikroORM) { }
#UseRequestContext()
async doSomething() {
// this will be executed in a separate context
}
}
Alternatively we can provide a callback that will return the MikroORM instance.
import { DI } from '..';
export class MyService {
#UseRequestContext(() => DI.orm)
async doSomething() {
// this will be executed in a separate context
}
}
Note that this is not a universal workaround, you should not blindly put the decorator everywhere - its actually the opposite, it should be used only for a very specific use case like CRON jobs, in other contexts where you can use middlewares this is not needed at all.
I faced a similar issue today when I upgraded the mikrorm setup from v4 to v5. After doing some RnD, I found the following changes helped me solve the mentioned error.
In the config object which is passed to the MikroORM.init call, pass the following property
allowGlobalContext: true
Don't directly use em to create database entry. Instead use the following code
const post = orm.em.fork({}).create(Post, {
title: "my first post",
});
The above changes should help you fix the error.
I am also very new to MikroORM. so, I am not sure why this error appears. But my uneducated guess is, they are restricting access to any changes to the global EntityManager em instance.
After doing some digging I found this solution:
yarn install dotenv
create a .env file in the root of the project
In your .env file paste the following:
MIKRO_ORM_ALLOW_GLOBAL_CONTEXT = true
Problem solved!

ServiceStack NativeTypesFeature AddResponseStatus

I'm writing a backend using ServiceStack. our main front end client is an Angular 2 application using TypeScript. To that end, we are using the DTOs that are generated by the services when hitting /types/typescript and /types/typescript.d. This all works fine and good using the JsonServiceClient... but it seems that the response status code is somehow wrapped up in the call and not returned as it as when using a standard XHR call.
Finding the AddResponseStatus configuration item, I changed the service configuration to add this on any DTO that didn't already have the property (which mine didn't):
var ntf = new NativeTypesFeature();
ntf.MetadataTypesConfig.AddResponseStatus = true;
Plugins.Add(ntf);
After refreshing the TypeScript reference, I can see that all DTO types returned now have a ResponseStatus property on them.
export class QueryReportResponse
{
Data: string;
ResponseStatus: string;
}
Here is a scrubbed return (removed the 'Data' portion) showing the property exists on the object:
<QueryReportResponse xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/blah.blah.ServiceModel.Messages">
<Data>
blah blah data here
</Data>
<ResponseStatus i:nil="true"/>
</QueryReportResponse>
Now, I assumed (wrongly so) that by doing this, some sort of status would be set 'automatically'. I'm obviously not right here, as this property is not set. My front end guy is asking to be able to see the status on all returned calls, like he was able to before when using straight XHR prior to using the JsonServiceClient, as now he cannot see the return status.
What is the intent of this field? I cannot set it manually, as it's added by ServiceStack dynamically at runtime. I can only assume that I would have to create my own base class return DTO of sorts and set that on the way back to the caller... can someone help me understand the purpose of this field? Thanks.
ServiceStack's Add TypeScript Reference is typically used with the TypeScript servicestack-client. The ResponseStatus is used in ServiceStack's Error Handling which is used to capture structured Error Information. It's not populated for successful responses and it's distinct from the HTTP Response Status code although if throwing a HTTP Error the ResponseStatus.ErrorCode will typically contain the HttpStatusCode enum string.
Adding ResponseStatus on DTOs
Adding the ResponseStatus on DTOs, e.g:
ntf.MetadataTypesConfig.AddResponseStatus = true;
Just adds the ResponseStatus on generated DTOs where they didn't previously exist. It doesn't have any effect on Response DTOs which already includes the ResponseStatus property, e.g:
public class MyResponse
{
public ResponseStatus ResponseStatus { get; set; }
}
Accessing HTTP Status Responses
Developers shouldn't care what the HTTP Status code is for successful responses (which is almost always 200 OK). ServiceStack's TypeScript JsonServiceClient will just return the Typed Response DTO for successful responses, e.g:
var response = await client.post(request)
They should only be interested for handling error responses, however it's expected to use the ResponseStatus.ErrorCode to determine the type of Error and apply application error handling logic, e.g:
try {
var response = await client.post(request)
} catch (e) {
console.log(e.responseStatus.errorCode);
}
If they really want the HTTP Status they can get it using a response filter, e.g:
var status = null;
try {
client.responseFilter = res => status = res.status;
var response = await client.post(request)
} catch (e) {
console.log(status, e.responseStatus.errorCode);
}

How to remove ContentType requirement from NServiceKit request

I am trying to make a RESTful web service using NServiceKit version 1.0.43. I want this to work without an outside service that is not including a ContentType in their header request. My web service is rejecting the calls with a "406 Unaccepted Content Type" although I have not set a default content type. How do I allow calls to this service without defining a ContentType?
I did something similar with a RequestFilterAttribute in ServiceStack 4.x. It may need some tweaking to work on NServiceKit's fork, but this gives you the general idea. If a Content-type header is not sent in, it defaults it to JSON:
public class ContentTypeFixFilter : RequestFilterAttribute
{
public override void Execute(IRequest req, IResponse res, object requestDto)
{
if (!req.Headers.AllKeys.Contains("content-type", StringComparer.CurrentCultureIgnoreCase))
{
req.ResponseContentType = MimeTypes.Json;
}
}
}
}

CORS on Web API and MVC 5 Controller: Upload images with fetch and FormData

I have an application that has the front and back ends running on different .NET projects.
The front end is an Aurelia web application running on ASP.NET 5. This Aurelia app (from now on The FrontEnd) gets all it's data from a Web API 2/MVC 5 application (henceforth, The BackEnd).
Since The FrontEnd and the BackEnd are different applications I have CORS setup, both for the Web API and in the Start.Auth.cs for the token bearer request.
The FronEnd is running on http://localhost:49850.
Now, for some code (this is all in the BackEnd)
Start.Auth.cs
The whole of the application resides behind a log-in form, so inside the Start.Auth.cs file, other than setting up the token-based authentication on the static Startup(), method I have a bit of middleware that adds the Access-Control-Allow-Origin header to the request on the one case where there is no token available yet: when we are requesting one.
public void ConfigureAuth(IAppBuilder app)
{
app.Use(async (context, next) =>
{
if (context.Request.Path.Value.Equals("/token"))
context.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "http://localhost:49850" });
await next();
});
app.UseCors(CorsOptions.AllowAll);
app.UseOAuthAuthorizationServer(OAuthOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
}
WebApiConfig.cs
Here I just added the EnableCorsAttribute so that it is enable globally.
var enableCors = new EnableCorsAttribute("http://localhost:49850", "*", "*");
config.EnableCors(enableCors);
Uploading files
Everything works fine; I can perform GET and POST requests to the Web API without a problem, the problem comes when trying to upload images.
To upload to files I have an action method in an ASP.NET MVC controller called FileControler.
FileController.cs
[HttpPost]
public ActionResult UploadImage(string id, string name = "")
{
var files = (from string fileName in Request.File
select Request.Files[fileName]
into file
where file != null
select DoSomethingWithTheFile(file, id)).ToList();
// ...
return Json(arrayWithFileUrls);
}
Calling the MVC controller
This is already part of The FrontEnd.
To call this method I use Aurelia's Fetch Client:
upload(url, data, files) {
let formData = new FormData();
for (let key of Object.keys(data)) {
formData.append(key, data[key]);
}
for (let i = 0; i < files.length; i++) {
formData.append(`files[${i}]`, files[i]);
}
return this.http.fetch(url, {
method: "POST",
body: formData,
headers: {
cmsDatabase: sessionStorage["cmsDatabase"]
}
}).then(response => {
return response.json();
}).catch(error => {
console.log(error);
});
}
And here's a call to the upload method above:
// files comes from an <input type="file" />
upload("http://localhost:64441/file/uploadImage", { id: id }, files)
.then((uploadedPhotos) => {
// do something with those file urls...
});
The Problem
All this works if I remove all CORS setup from WebApiConfig.cs, and in Startup.Auth.cs I substitute the call to the middleware for app.UseCors(CorsOptions.AllowAll);, so I know my code is ok, but as soon as I use the CORS setup described above, everything works except the call to http://localhost:64441/file/uploadImage, returning even a 404:
Fetch API cannot load http://localhost:64441/file/uploadForSku.
Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin'
header is present on the requested resource.
Origin 'http://localhost:49850' is therefore not allowed access.
The response had HTTP status code 404. If an opaque response serves your needs,
set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
The "funny" thing is that if I try calling that url with, for intance, REST Console I don't get a 404.
I've tried adding the [HttpOptions] attribute to the action method; I've tried creating ActionFilterAttributes as described here and here, and even setting uip CORS from within the web.config, but to no avail.
I know the problem is that FileController is a regular MVC Controller instead of a Web API controlle, but shouldn't it still be possible to get CORS working?
have you tried this
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
in ApplicationOAuthProvider.cs file

ajax post security in laravel?

I am developing an application in laravel 5.1, I need to use sensitive user data and i was wondering about security when using ajax posts instead of a standard post. is it recommended using ajax, is there a way of performing some kind of protected ajax posts? Thanks :D
In laravel 5.1 you can use the HTTP Middleware in order to create something similar to the filters of older version.
1: Define Middleware
namespace App\Http\Middleware;
use Closure;
class BeforeMiddleware
{
public function handle($request, Closure $next)
{
// Check all your ajax stuff
return $next($request);
}
}
Inside the definition you can check wheter the request is Ajax, or other (have a look at the Class Reference) and define, for example, if the user has authorization to that specific route.
2: Assign middleware to routes
// Within App\Http\Kernel Class...
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'myMiddleware' => \Path\To\The\MiddleWare::class,
];
3: use the middleware key in the route options array
Route::post('your/route', ['middleware' => 'myMiddleware', function () {
//
}]);

Resources