I'm developing server(console app) on latest .Net 6 platform, using AspNetCore.signalR and in OnConnectedAsync method I want to read headers present in HttpContext, but I can't get HttpContext, I've tried:
var httpContext = Context.GetHttpContext();
But this throws compilation error. Like this method does not exist in this namespace anymore(namespace: Microsoft.AspNetCore.SignalR).
I also tried following approach:
var features = Context.Features.Get<HttpConnectionFeature>();
But this only gives info about Local/Remote IP Addresses which is useless when using proxy.
So I want to read all context headers, like User-Agent, Remote IP address, X-Forwarded-For and etc.
Any suggestions/solutions?
public override Task OnConnectedAsync()
{
var httpCtx = Context.GetHttpContext();
var headers = httpCtx.Request.Headers;
return base.OnConnectedAsync();
}
The problem was I was using Microsoft.AspNetCore.SignalR.Core package and it didn't contain GetHttpContextExtensions and I could not reach the HttpContext. So I replaced the package with Microsoft.AspNetCore.SignalR.
Most of the signalR packages on nuget are deprecated, like this one https://www.nuget.org/packages/Microsoft.AspNetCore.SignalR.Core
So just make sure to uninstall any nuget packages of SignalR and instead update your csproj file to include the following:
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
Related
I am trying to create middleware which performs some checking for particular requests.
For example, I have such routes:
api/Test/{paramToCheck}/aaa
api/Test/bbb/ccc
and I have these requests:
http://some-host-and-port/api/Test/1234/aaa
http://some-host-and-port/api/Test/bbb/ccc
Now inside my middleware I want to check if request contains {paramToCheck} and get value of this parameter.
When I set breakpoint inside InvokeAsync I can see httpContext.Request.RouteValues property containing all needed data (Keys contains "paramToCheck" and Values contains its value).
But in code I can't access this property, I get error:
Error CS1061: 'HttpRequest' does not contain a definition for
'RouteValues' and no accessible extension method 'RouteValues'
accepting a first argument of type 'HttpRequest' could be found (are
you missing a using directive or an assembly reference?)
var value = httpContext.Request.RouteValues["paramToCheck"];
How can I access this property or how can I perform needed check?
Code:
public class MyMiddleware
{
private readonly RequestDelegate _next;
public MyMiddleware
(
RequestDelegate next
) => this._next = next;
public async Task InvokeAsync(HttpContext httpContext)
{
var value = httpContext.Request.RouteValues["paramToCheck"]; // error here
//... some logis with value
await this._next(httpContext);
}
}
EDIT
Middleware is inside netstandard2.1 class library and it cannot be moved to api project as it is common and should be used by several api projects.
UPDATE
Seems like currently it cannot be achieved as RouteValues propery was added in Microsoft.AspNetCore.Http.Abstractions 3.0.0 which is inside NetCoreApp 3 metapackage. And there is no possibility to install this package in netstandard 2.1 project because the latest version is 2.2.0.
Just encountered the same problem today.
This is hacky but it works
IReadOnlyDictionary<string, object>? routeValues = ((dynamic)context.Request).RouteValues as IReadOnlyDictionary<string, object>;
Using a class library, the answer for me was to upgrade to using .netcore 3.1's Microsoft.AspNetCore.App instead of Microsoft.AspNetCore.Http.Abstractions v2.2
As stated here, .net core 3 did away with all the small packages, so I replaced
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
</ItemGroup>
with
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App"/>
</ItemGroup>
and then I could access the route like so:
HttpContext.Request.RouteValues["version"];
where {version} was set in the route.
sounds like you trying to access this from a service implementation which does not have access to httpContext, am i correct in saying to have this outside of your api project.
if you do httpContext.Request.RouteValues["paramToCheck"]; in controller does it works... then to get it to work , do this in controller and pass the result to the lib.
httpContext has "binding"* to BaseController or ControllerBase... what ever its call.. basically the wiring which you are expecting is not done in your lib... so httpContext has no web context at all, there is a much better way to word this... all, but you get the just.
You can use the extension .GetRouteData() from RoutingHttpContextExtensions which will provide you a RouteData instance. This extension is part of Microsoft.AspNetCore.Routing package.
The RouteData contains a property member of type RouteValueDictionary called Values.
var routeData = httpContext.GetRouteData();
if (routeData.Values.TryGetValue("paramToCheck", out object value))
{
// ... Do some logic with the value
}
To understand a bit more about the RoutingHttpContextExtensions and RouteData check the source code at
https://github.com/dotnet/aspnetcore/tree/3.0/src/Http/Routing
Alexander Ivanov's answer:
routeValues = ((dynamic)context.Request).RouteValues as IReadOnlyDictionary<string, object>;
worked for me, thanks! It took me a little to get it working, however, as the following packages were required:
Microsoft.AspNetCore.Http.Abstractions
Microsoft.CSharp
Including this additional information in the hopes it saves someone some time.
I'm currently tapping into Blazor, and want to move my code so it's more readable and reusable. In my razor component, the Method works flawlessly - in a Class, it doesn't.
In my component, I can simply use this:
response = await Http.GetJsonAsync<T>(Uri);
In my Class, Visual Studio complains that System.Net.Http's HttpClient contains no definition for GetJsonAsync - but I'm getting a typed response, so I want to deserialize it properly.
As of preview 8, you need:
<PackageReference Include="Microsoft.AspNetCore.Blazor.HttpClient" Version="3.0.0-preview8.19405.7" PrivateAssets="all" />
NOTE: This was correct at the time, but as of Blazor version 3.1.0 this may have changed again so that now you most likely want the System.Net.Http.Json package. See the answer from #JohnB below.
Great question. And I'm assuming Darrell's answer (and the others) was 100% correct as of version 3.0.0 (Blazor WebAssembly preview).
However, as for version 3.1.301 I think the package location has changed.
Currently, the namespace is: System.Net.Http.Json
That will give you access to: HttpClientJsonExtensions
A. If you want to put that code into a separate class within your Blazor WebAssembly project, all you need is to put this at the top of your class file:
using System.Net.Http; // for HttpClient
using System.Net.Http.Json; // for HttpClientJsonExtensions
B. If you want to put that class into a separate project (.NET Core library) then you need to add the NuGet package also:
NuGet package: System.Net.Http.Json
Then you can use it in your class like in the example below. Obviously these extension methods are doing serialization, but what's interesting is that the package doesn't depend on Newtonsoft.Json because it uses the new System.Text.Json instead.
using System;
using System.Net.Http;
using System.Net.Http.Json;
using System.Threading.Tasks;
namespace MyClassLibrary
{
public class MyClass
{
public async Task MyMethod()
{
string baseAddress = "http://localhost:57012/";
var httpClient = new HttpClient() { BaseAddress = new Uri(baseAddress) };
var myPocos = await httpClient.GetFromJsonAsync<MyPoco[]>("api/mypocos");
foreach (var myPoco in myPocos)
Console.WriteLine($"Id: {myPoco.Id}, Name: {myPoco.Name}");
}
}
public class MyPoco
{
public int Id { get; set; }
public string Name { get; set; }
}
}
Article about System.text.json VS Newtonsoft.json versus Utf8Json.
As of today the correct answer is:
using System.Net.Http.Json
and
GetFromJsonAsync()
Just download Microsoft.AspNetCore.Blazor.HttpClient package.
It's worth noting that "include prerelease" must be checked in order to find this package. I just spent a half hour getting fairly angry that the package wasn't found and scouring google to find out why!
For Blazor, there is an extension class (Microsoft.AspNetCore.Blazor.HttpClientJsonExtensions) available to get you the same extension methods.
Ref: https://learn-blazor.com/architecture/rest-api/
I have a problem to integrate swagger ui with my web api, and i don't have any idee what is the problem.
When i call in the browser the swagger, the page http://localhost:56381/swagger/ui/index is like in this screenshot
In the SwaggerConfig.cs file i have this code:
[assembly: PreApplicationStartMethod(typeof(SwaggerConfig), "Register")]
namespace dummyNamespace
{
public class SwaggerConfig
{
public static void Register()
{
var thisAssembly = typeof(SwaggerConfig).Assembly;
GlobalConfiguration.Configuration
.EnableSwagger(c => c.SingleApiVersion("v1", "Test API"))
.EnableSwaggerUi();
}
}
}
I follow this tutorial: http://www.wmpratt.com/swagger-and-asp-net-web-api-part-1/ . But not working.
I don't now what is wrong with my configuratio.
I use .net framework 4.5.2, Web api 2.0 and Swashbuckle.5.5.3 version
Update:
When I call this url
http://localhost:56381/swagger/docs/v1
Return this image:
Update1:
After i put this code in my WebApiConfig.cs:
var appXmlType = config.Formatters.XmlFormatter.SupportedMediaTypes.FirstOrDefault(t => t.MediaType == "application/xml");
config.Formatters.XmlFormatter.SupportedMediaTypes.Remove(appXmlType);
Now the http://localhost:56381/swagger/ui/index return this json:
{
"statusCode": 200
}
Any idee how to make make http://localhost:56381/swagger/ui/index return this page:
The page is from a test project.
After reading the tutorial you posted, it looks like somehow your root URL may be different than what swagger expects. From the swagger config file:
// By default, the service root url is inferred from the request used to access the docs.
// However, there may be situations (e.g. proxy and load-balanced environments) where this does not
// resolve correctly. You can workaround this by providing your own code to determine the root URL.
//
//c.RootUrl(req => GetRootUrlFromAppConfig());
If that is not the case, it could be that the swashbuckle nuget install is somehow corrupted. Try removing the nuget package and reinstalling it.
I'd like to define view components (which are new in ASP.NET MVC 6) in a separate assembly from the MVC 6 web startup project so that I can reuse them in multiple web projects. A sample solution might look like this:
BookStore.Components (houses common view components)
BookStore.Web1 (references BookStore.Components)
BookStore.Web2 (references BookStore.Components)
I created a new Class Library (Package) and created a view component inside. I also created the view following the nested folder convention. My BookStore.Components project looks like this:
When I try to invoke this view component from my web project:
#Component.Invoke("BookOfTheMonth")
...I get a 500 error with an empty content body. It seems like the ViewComponent class is discovered, but the razor view for the component isn't.
I also tried to extend DefaultViewComponentDescriptorProvider so that view components from the BookStore.Components assembly can be discovered:
Defined an AssemblyProvider
public class AssemblyProvider : IAssemblyProvider
{
public IEnumerable<Assembly> CandidateAssemblies
{
get
{
yield return typeof(AssemblyProvider).Assembly;
yield return typeof(BookStore.Components.BookOfTheMonthViewComponent).Assembly;
}
}
}
Registered AssemblyProvider using Autofac
builder.RegisterType<AssemblyProvider>()
.AsImplementedInterfaces();
builder.RegisterType<DefaultViewComponentDescriptorProvider>()
.AsImplementedInterfaces();
I'm not sure if the registration of DefaultViewComponentDescriptorProvider above is needed or not, so I tried with and without it, but I still get a 500 error on a page where the view component is invoked.
How can I invoke a view component that lives in a separate assembly from the MVC6 web project?
Update 2017-03-09
Things have changed a bit in Visual Studio 2017 using MS Build. Luckily it's much simpler. Here's how to get this to work:
In the external assembly, add this to the csproj file:
<ItemGroup>
<EmbeddedResource Include="Views/**/*.cshtml" />
</ItemGroup>
In the main web project, add this NuGet package:
Microsoft.Extensions.FileProviders.Embedded
Then in Startup, add the external assembly to the list of File Providers:
services.Configure<RazorViewEngineOptions>(options =>
{
options.FileProviders.Add(new EmbeddedFileProvider(
typeof(SampleClassInAssembly).Assembly
# Prior to .Net Standard 2.0
# typeof(SampleClassInAssembly).GetTypeInfo().Assembly
));
});
I'll leave the original answer below for now, in case people are still trying to get this to work with older versions of .Net Core and project.json.
================================================================
Here are the steps to make this work.
Make sure your view structure in the components assembly is the same as your web project. Note that there was a mistake in the screenshot that I posted along with my question.
Register CompositeFileProvider in Startup.cs of the web project:
services.Configure<RazorViewEngineOptions>(options =>
{
options.FileProvider = new CompositeFileProvider(
new EmbeddedFileProvider(
typeof(BookOfTheMonthViewComponent).GetTypeInfo().Assembly,
"BookStore.Components"
),
options.FileProvider
);
});
Both CompositeFileProvider and EmbeddedFileProvider are new, so you'll need to get these from the aspnetvnext NuGet feed. I did this by adding this source:
Add the dependencies in project.json:
"Microsoft.AspNet.FileProviders.Composite": "1.0.0-*",
"Microsoft.AspNet.FileProviders.Embedded": "1.0.0-*",
Lastly, add this to the project.json of the Components assembly:
"resource": "Views/**"
That should be enough to get this working.
Here is a working demo:
https://github.com/johnnyoshika/mvc6-view-components/tree/master
This answer was formulated from this discussion here: https://github.com/aspnet/Mvc/issues/3750
Update 2016-01-15
There is currently one painful problem with external view components. Any changes you make to the view cshtml file does not automatically get recompiled. Even a forced Visual Studio clean and rebuild doesn't do it. You need to change a .cs file in the components assembly in order to trigger a view recompilation, but it looks like this is something that will be corrected in the future. The reason for this problem is explained here: https://github.com/aspnet/Mvc/issues/3750#issuecomment-171765303
I have done some researching on Github and found that PhysicalFileProvider (link) IFileInfo GetFileInfo(string subpath) method is used by Razor engine (link) for getting real files to compile.
Current implementation of this method
public IFileInfo GetFileInfo(string subpath)
{
if (string.IsNullOrEmpty(subpath))
{
return new NotFoundFileInfo(subpath);
}
// Relative paths starting with a leading slash okay
if (subpath.StartsWith("/", StringComparison.Ordinal))
{
subpath = subpath.Substring(1);
}
// Absolute paths not permitted.
if (Path.IsPathRooted(subpath))
{
return new NotFoundFileInfo(subpath);
}
var fullPath = GetFullPath(subpath);
if (fullPath == null)
{
return new NotFoundFileInfo(subpath);
}
var fileInfo = new FileInfo(fullPath);
if (FileSystemInfoHelper.IsHiddenFile(fileInfo))
{
return new NotFoundFileInfo(subpath);
}
return new PhysicalFileInfo(_filesWatcher, fileInfo);
}
private string GetFullPath(string path)
{
var fullPath = Path.GetFullPath(Path.Combine(Root, path));
if (!IsUnderneathRoot(fullPath))
{
return null;
}
return fullPath;
}
We can see here that absolute paths nor permitted and the GetFullPath method combines path with Root which is your main web application root path.
So I assume that u can't open ViewComponent from other folder than the current one.
As of .NetCore v3.x:
[Optional] Remove Microsoft.Extensions.FileProviders.Embedded nuget package
Install Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation nuget package
Call .AddRazorRuntimeCompilation(), e.g: services.AddMvc().AddRazorRuntimeCompilation()
Instead of
services.Configure<RazorViewEngineOptions>(options =>
{
options.FileProviders.Add(new EmbeddedFileProvider(
typeof(SampleClassInAssembly).Assembly
));
});
Add this:
services.Configure<MvcRazorRuntimeCompilationOptions>(options =>
{
options.FileProviders.Add(new EmbeddedFileProvider(
typeof(SampleClassInAssembly).Assembly
));
});
And you are good to go.
Related github issue
First off, of all the NuGet code, I'm trying to figure out which one to reference.
The main question is, given a NuGet package name, is there a programmatic way to retrieve the versions from the NuGet feed and also the latest version for general consumption?
For example, given a package name of ILMerge, it would be nice to get the latest package version of 2.13.307.
// Pseudo code, makes a lot of assumptions about NuGet programmatic interfaces
PackageRef currentVersion = nugetlib.getpackageinfo(args[0]);
Console.WriteLine("Package Id: '{0}':", pkg.Id);
Console.WriteLine(" Current version: {0}", pkg.Version);
Console.WriteLine(" Available versions: {0}", String.Join(",",pkg.Versions.Select(_=>_)));
Use the NuGet core package:
string packageID = "ILMerge";
// Connect to the official package repository
IPackageRepository repo = PackageRepositoryFactory.Default.CreateRepository("https://packages.nuget.org/api/v2");
var version =repo.FindPackagesById(packageID).Max(p=>p.Version);
Reference: Play with Packages, programmatically!
There exist a quite nice NuGet API to accomplish both.
a) Retrieving the NuGet package versions (for the Newtonsoft.Json package in following example):
GET https://api.nuget.org/v3-flatcontainer/Newtonsoft.Json/index.json
b) Downloading a certain version of the NuGet package - e.g.
GET https://api.nuget.org/v3-flatcontainer/utf8json/1.3.7/utf8json.1.3.7.nupkg
Please try to copy the URL to the browser and you could see the results of the examples...
To get more information about API, please visit the
Package Content
The following code example could read the versions of a package (using the Microsoft.AspNet.WebApi.Client NuGet package which provides HttpContent's ReadAsAsync<T> extension for parsing the JSON result to an appropriate class - the VersionsResponse in this example)
using System;
using System.Net.Http;
using System.Threading.Tasks;
namespace GetNuGetVer
{
class VersionsResponse
{
public string[] Versions { get; set; }
}
class Program
{
static async Task Main(string[] args)
{
var packageName = "Enums.NET";
var url = $"https://api.nuget.org/v3-flatcontainer/{packageName}/index.json";
var httpClient = new HttpClient();
var response = await httpClient.GetAsync(url);
var versionsResponse = await response.Content.ReadAsAsync<VersionsResponse>();
var lastVersion = versionsResponse.Versions[^1]; //(length-1)
// And so on ..
}
}
}
To get rid of Microsoft.AspNet.WebApi.Client (with dependency to Newtonsoft.Json), System.Text.Json can be used out of the box (since .NET Core 3.0) with code changes as follows:
using System.Text.Json;
...
var response = await httpClient.GetAsync(url);
var versionsResponseBytes = await response.Content.ReadAsByteArrayAsync();
var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
var versionsResponse = JsonSerializer.Deserialize<VersionsResponse>(versionsResponseBytes, options);
var lastVersion = versionsResponse.Versions[^1]; //(length-1)
or just a different JSON parser based on your own preferences.
As described on NuGet2, Nuget.Core is for version 2 of NuGet.
Version 3 of the NuGet client library has moved to Nuget.Client. See the NuGet API v3 documentation for more information.
NuGet Client SDK