#Odata.Context - Change Base URL - asp.net-core

I've searched high and low and all the answers (especially here) point towards old .netcode (specifically webapi2).
I need to have the #odata.context url changed in my response, as my service is sitting behind a proxy.
I can't find a clean way to do it, apart from altering the url at the request level - is there no clean netcore odata implementation to do it?
Implementation is pretty standard:
Using 8.0.12
and openApi 7.0.2
services
.AddControllers()
.AddOData(options => options
.Select()
.Filter()
.OrderBy()
.Expand()
.Count()
.OrderBy()
.SetMaxTop(500)
.SkipToken()
.AddRouteComponents("odata", GetEdmModel()));

Related

Serilog using EnrichDiagnosticContext with additional properties not being logged in SignalR Hub

I have recently implemented Serilog logging into my ASP.NET Core/.NET5 web app that uses SignalR. I'm using the Elasticsearch sink and everything is largely working as expected. I decided to add some additional HttpContext properties to be logged on each request, so I went down the road of extending the call to UseSerilogRequestLogging() in StartUp.cs as to enrich the diagnostic context with a couple of extra properties (mainly because this seemed like the simplest way to do it):
app.UseSerilogRequestLogging(options =>
{
options.EnrichDiagnosticContext = (diagnosticContext, httpContext) =>
{
diagnosticContext.Set("HttpRequestClientIP", httpContext.Connection.RemoteIpAddress);
diagnosticContext.Set("UserName", httpContext.User?.Identity?.Name == null ? "(anonymous)" : httpContext.User.Identity.Name);
};
});
At first, this seemed to work as expected until I noticed it wasn't always working. I really want the extra properties logged on all log records written, and it seems to work fine on log records that are written automatically by Serilog when typical HTTP GETs, HTTP POSTs, etc. occur... But in my Signalr Hub class, I have a couple of places where I'm manually writing my own log records like Logger.Log(LogLevel.Information, "whatever.."), but these extra properties are simply not there on these records.
What am I missing here? Is it something about this being in a Signalr Hub that makes them unavailable? Or perhaps there's something I'm doing wrong with my Logger.Log() calls?
Any ideas would be appreciated.
Thanks-
It's not gonna to work with signalR.
Behind the screen, app.UseSerilogRequestLogging make use of a middleware in the request pipeline, that call RequestLoggingMiddleware as what you can see in detail here.
SignalR use the first Http request to setting to connection up to websocket, which won't goes through the pipeline at all. Therefore, doesn't have anything to do with RequestLoggingMiddleware, which you are using to logging out the request.
I finally ended up going with a couple of custom Enrichers. I did experiment briefly with middleware vs enrichers and they both seem to work as expected. Both always added the additional properties to all log entries. I'm still not quite sure I understand why the DiagnosticContext option behaves the way it does, unless it is simply due to the logging in question being in a SignalR hub as #Gordon Khanh Ng. posted. If that were the root of the problem though, you wouldn't think the enrichers or middleware would work either.

Marshmallow and Flask-RESTPlus, how should they be used along?

I'm using Flask-Restplus to marshal responses in a Flask server. I also began using this package to parse HTTP requests from the client, when I stumbled about this huge warning on their site:
Warning
The whole request parser part of Flask-RESTPlus is slated for removal
and will be replaced by documentation on how to integrate with other
packages that do the input/output stuff better (such as marshmallow).
I then switched to Marshmallow to validate/parse the HTTP client requests. Thus, the workflow in my server is:
Client request (HTTP GET/POST) ...
--> process request with Marshmallow and validate/format data
--> do stuff with DB (read, update, create)
--> Format output response with Flask RESTPLUS
... Client response
So far this works well. However, is this the correct way to use Flask RESTPLUS and Marshmallow along? On the marshmallow website, there is no clear direction towards a specific use of this package. The documentation just says:
Marshmallow is an ORM/ODM/framework-agnostic library for converting
complex datatypes, such as objects, to and from native Python
datatypes.
I have seen examples in the web where people use Marshmallow to format the output response, and Flask to validate expected data (with #api.expect). Which approach is better?
Also, I wonder if this even makes sense to use Flask RESTPLUS at all? It seems the only interest of this library is to have the Swagger UI doc automatically generated. Other than that, Marshmallow can do everything that Flask RESTPLUS does. So maybe I missed out something, can anyone help or comment?
Thanks
Take further notice of the warning displayed on the website:
Don’t worry, if you have code using that now and wish to continue doing so, it’s not going to go away any time too soon.
The developers will post documentation how to integrate best Marshmellow in the future.
So far this works well. However, is this the correct way to use Flask RESTPLUS and Marshmallow along? On the marshmallow website, there is no clear direction towards a specific use of this package
Flask is a microframework: what this means for you is that much of the implementation of your application is up to the programmer because it lacks most of the functionality which is common to expect in a full-fledged web application framework (eg. Django, Pyramid et al.) and there's not "one way and only one way" of doing things in it. Implementation details like data validation are up to you to provide via plugins, libraries or even implementing them yourself (not recommended).
I wonder if this even makes sense to use Flask RESTPLUS at all?
From what I've seen in the Quick start page of Flask-RESTPlus, it provides useful models that facilitates exposing REST verbs for resources, endpoints, arg parsing and data formatting. But again, this question depends mostly on you and your application requirements.

How to use HttpResponseFeature in a ASP.net Core Middleware

I just found out that "RequestFeatures" is a thing in ASP.net Core, news to me..
Anyways..
I have created a middleware that needs to alter the response body and the headers provided with the response.
Im used to do this by alterntiv it directly on the HttpContext context-object provided as an argument to the Invoke-method.. however I read somewhere that context.Features is the way to go due to optimizations and what not.. (is this true?, I get that its alot easiter to test the Features, than to "mock" an entire HttpContext which has been historically a painful thing to do..) So I created my own implementation of the HttpResponseFeature and registred it in my Invoke method using:
httpContext.Features.Set<IHttpResponseFeature>
(
//Registering my own HttpResponseFeature that takes an argument..
new MyHttpResponseFeature(httpResponseMessage)
);
However, the OnCompleted or the OnStarting-methods never runs. I have added a few breakpoints to validate this, but the breakpoints are never hit. Am I missing something?
Turns out that the FeatureCollection/RequestFeatures is a "new" thing if your building your very own custom HTTP server ontop of ASP.net Core.
An article that covers this fairly well is this one:
https://reynders.co/use-iserver-from-aspnet-core-to-create-your-own-web-server/

How can I run Zend Framework code alongside legacy (non-ZF) code on the same server on the same HTTP port?

I have a large codebase that I am trying to eventually convert to Zend-Framework-powered stack.
I at times write new modules to where I have a choice:
keep writing using legacy routing/initialization/etc
somehow figure out how to use ZF for the new module only while the rest of the legacy code works "as before"
Is this possible?
How?
To give you an idea, code I have now uses proprietary multiple routing files, where everything in ZF goes through one single router file.
So legacy code is called like so i.e.:
http://legacy:80/index.php?route=product
May be similar to zend framework 2 in a subdirectory
Zend Middleware approach
I was able to follow https://docs.zendframework.com/zend-mvc/middleware/ and implement an IndexMiddleware class. I can see that IndexMiddleware::process() method is being called. But I am not certain how to go further, and how to engage my legacy web application to return data as before.
MiddlewareListener.
Legacy App - index.php
$module = filter($_GET['p']);
if (!empty($module))
$inc = 'portal/{$module}.php'; //prep a legacy module
require($inc); //run module
There are many solutions there... Depends on how much new code you have, and addresses you want.
Long story short, you could work at the server level (aliases, rewrite, etc), or at the PHP code level.
Something you could do is use the index.php from the Zend Skeleton for instance, and the default url routing through index.php. Then look at the application lifecycle, especially the route event. I believe that's a good point to add a listener that would dispatch the old application. You can find numbers of Listeners in the Zend MVC code to base your code on (look at the middleware one for instance).

Symfony - fallback to another application if Symfonfy app can not handle the request

We have an old Yii application along with new Symfony one.
The basic idea is simple - I need to check if there is a route matching in Symfony application then it is cool, if not then bootstrap Yii application and try to handle the request with it.
The main idea to not instantiate AppKernel (and do not load autoload.php - since there is two different autoload.php for each project) before I am sure there is route matching.
Can I do it somehow?
We've done this before with legacy applications.
There are two approaches you can take.
Wrap your old application inside a symfony project (recommended).
Unfortunately this will indeed load the symfony front-controller and kernel. No way around that. You need to make sure that symfony can't handle the request and to do that the kernel needs to be booted up.
Use sub-directories and apache virtual hosts to load one application vs the other as needed.
Given option 1,
You can either create your own front controller that loads either symfony or yii by reading routes (from static files if using yml or xml, or annotations which will be more complex) OR EventListener (RequestListener) that listens to the HttpKernelInterface::MASTER_REQUEST and ensures that a route can be returned.
Creating your own front controller is the only way that you can make it not load the symfony kernel, but it will require you to write something that understands the routes in both frameworks (or at least symfony's) and hands off the request appropriately.
Event listener example:
public function onkernelRequest(GetResponseEvent $event)
{
if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
return;
}
... Code to continue normally, or bootstrap yii and return a custom response... (Can include and ob_start, or make an http request, etc)
}
public function getSubscribedEvents()
{
return [
KernelEvents::REQUEST => ['onKernelRequest']
];
}
As you see, the kernel needs to be booted to ensure symfony can't serve the route. Unless creating your own front controller (as stated above).
A third approach would be to create a fallback controller, which would load up a specified URL if no route was found within symfony. Although this approach is generally used for legacy projects that lack a framework and use page scripts instead of proper routes, and definitely requires the use/help of output buffering.
The EventListener approach gives you the opportunity to create a proper Request to hand off to yii, and using what is returned to create a Response as proper symfony object (can also use ob or other options).
Thank you.
This is an alternative to vpassapera's solution -http://stovepipe.systems/post/migrating-your-project-to-symfony