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/
Related
I currently use Azure App Configuration to store all the config data. When i read the data, i would like to use Newtonsoft.Json instead of the default System.Text.Json to correctly transform my data to custom types.
Unfortunately, i cannot find a way to tell the HostBuilder in the Program.cs file to use Newtonsoft.Json instead of the System.Text.Json. All my converters are written using Newtonsoft.Json and i really would like to not migrate them all to System.Text.Json.
As an example:
public Enum SampleEnum
{
[Description("Sample")] SampleAbc
}
public class SampleConfig
{
public SampleEnum ConfigEnumA {get; set;}
}
// configuration is the IConfiguration object from Microsoft.Extensions.Configuration
var sampleConfig = new SampleConfig()
configuration.GetSection("section").bind(sampleConfig);
The Description value Sample is what comes from Azure App Configuration as a string and ideally my current Newtonsoft.Json converters should transform it to SampleAbc enum value when binding the object SampleConfig. This allows me to be type safe in code.
This means that ConfigEnumA should have a value of SampleEnum.SampleAbc instead of Sample
I have already tried using but it did not work although i am working with HTTP Triggers and not a web application
var hostBuilder = new HostBuilder().ConfigureServices(services =>
{
services.AddMvc().AddNewtonsoftJson(options =>
{
options.SerializerSettings.Converters = <my-custom-converters>
}
)
});
if there is no way to use Newtonsoft.Json in Azure Function apps that arent Mvc applications, then can someone help with achieving the same behaviour with System.Text.Json?
Thanks for the help.
Cheers.
AFAIK, Services.AddMvcCore().AddJsonOptions(...) is for System.Text.Json whereas builder.services.AddMvcCore().AddNewtonsoftJson(options => can be used for Newtonsoft.json.
If you want to use Newtonsoft, add Microsoft.AspNetCore.Mvc.NewtonsoftJson as a dependency from NuGet which contains AddNewtonsoftJson() extension.
dotnet add package Microsoft.AspNetCore.Mvc.NewtonsoftJson --version 7.0.0
Thanks to #Nate1zn, I found how to use Newtonsoft.Json in Azure Function apps, you can add a startup to your function project as below:
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection
[assembly: FunctionsStartup(typeof(NewtonsoftjsonfunctionApp.functionsample))]
namespace NewtonsoftjsonfunctionApp
public class functionsample : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.services.AddMvcCore().AddNewtonsoftJson(options =>
{
options.SerializerSettings.//json settings
}
}
}
I try to make a class with NancyModules and GET string on URL but method 'Get' tells that:
"Error CS0021 Cannot apply indexing with [] to an expression of type
'method group' ...."
My Code:
using System; using System.Collections.Generic; using System.Linq;
using System.Web; using Nancy; using System.Text;
namespace SinglePageApp1 {
public class BloodPresureNancy : NancyModule
{
public BloodPresureNancy()
{
// Get dasn't work
Get["/"] = _ => "Heloooo";
}
}
}
I add references: Nancy, Nancy.Hosting.asp and it isn't working.
What version of Nancy are you currently using? That syntax should work on versions 1.x. However, I think that Nancy recently made a change to the way that you register routes for their upcoming 2.0 release. If you take a look at the samples they have on github https://github.com/NancyFx/Nancy/blob/master/samples/Nancy.Demo.Hosting.Self/TestModule.cs. You will see that you don't index into the different verbs anymore like you are doing above, you actually reference them like you would a Method. Try changing your code to be
Get("/", _ => {
//do work here
});
instead and see if that works for you.
See https://github.com/NancyFx/Nancy/pull/2441
Specifically:
the wiki will not be updates as the 2.0 packages comes out of pre-release, until then all changes are considered as being pending =)
Ie. The magic custom indexer syntax that allowed you to do this:
Get["/"] = ...
Is gone in the Nancy 2.x releases.
However, all the documentation currently still refers to the current (ie. 1.4.x versions); so...
tldr; That syntax is old and gone in the new version of Nancy. Use Get(...), Post(...), etc if you're using the new version of Nancy.
While this is most likely not the right way of doing it, it does work:
Get("/test/{category}", parameters => { return "My category is " + (Nancy.DynamicDictionaryValue)parameters.category; });
Going to http://localhost/test/hello will return "My category is hello"
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
I can't seem to find an equivalent in Nancy for System.Web.HttpContext.Current.Server.MapPath() in the Nancy framework.
I just want to load a textfile relative to the application service.
I see this in the assembly
using Nancy;
using System;
namespace Nancy.Hosting.Self
{
public class FileSystemRootPathProvider : IRootPathProvider, IHideObjectMembers
{
public FileSystemRootPathProvider();
public string GetRootPath();
}
}
I'm not sure how to use.
update: I just figured out anything I need to load can just be read/written from the bin/relase/ directory. Is that the assumed way to do it in a Nancy Self Hosting environment? I guess that would make sense.
You can take a dependency on IRootPathProvider and use that to call GetRootPath() that will give you the root of your application and you can add from there (I would recommend using Path.Combine)
If you need this in a static class (such as an HtmlHelpers extension) where the IRootPathProvider dependency can't be injected, at least AFAIK, you can use AppDomain.CurrentDomain.BaseDirectory which is what DefaultRootPathProvider uses under the hood for .Net 4.x: https://github.com/NancyFx/Nancy/blob/master/src/Nancy/DefaultRootPathProvider.cs
I know there are several similar topics like this on this site, but I can't find a solution that works. I have a solution called 'SportsStore' and it contains 3 projects, ALL that use the full .NET 4 framework. The projects are named 'SportsStore.Domain', 'SportsStore.UnitTests' and 'SportsStore.WebUI'.
Within the 'SportsStore.WebUI' project, I created a folder called 'Infrastructure' and in it I have a class called 'NinjectControllerFactory.cs' The complete code for it is below. Note the last 'using' statement at the top: 'using SportsStore.Domain.Abstract'. My program will NOT compile and it tells me the namespace does not exist. Intellisense recognizes 'SportsStore' but only says 'WebUI' is my next option. It will not recognize 'SportStore.Domain' at all. I have tried cleaning, rebuilding, closing, opening, rebooting, changing frameworks back to Client for all projects and then back to Full, and nothing seems to work.
Bottom line is I'm trying to get access to my IProductRepository.cs repository file which is part of the SportsStore.Domain.Abstract namespace in the 'SportsStore.Domain' project.
I'm hoping this is something easy to correct? Thanks in advance!
using System;
using System.Collections.Generic;
using System.Web.Mvc;
using System.Web.Routing;
using System.Linq;
using Ninject;
using Moq;
using SportsStore.Domain.Abstract;
//To begin a project that uses Ninject and/or Moq (mocking data) you
//need to add reference to them. Easiest way is to select 'View', then
//'Other Windows', and 'Package Manager Console'. Enter the commands:
//Install-Package Ninject -Project SportsStore.WebUI
//Install-Package Ninject -Project SportsStore.UnitTests
//Install-Package Moq -Project SportsStore.UnitTests
//We placed this file in a new folder called 'Infrastructure' within the
//'SportsStore.WebUI' project. This is a standard way to define what we
//need to do with Ninject since we are going to use Ninject to create our
//MVC application controllers and handle the dependency injection (DI).
//To do this, we need to create a new class and make a configuration
//change.
//Finally we need to tell MVC that we want to use this class to create
//controller objects, which we do by adding a statement to the
//'Global.asax.cs' file in this 'SportsStore.WebUI' project.
namespace SportsStore.WebUI.Infrastructure
{
public class NinjectControllerFactory : DefaultControllerFactory
{
private IKernel ninjectKernel;
public NinjectControllerFactory()
{
ninjectKernel = new StandardKernel();
AddBindings();
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
return controllerType == null
? null
: (IController)ninjectKernel.Get(controllerType);
}
private void AddBindings()
{
//During development, you may not want to hook your IProductRepository to
//live data yet, so here we can create a mock implementation of the data
//and bind it to the repository. This is MOQ in work - great tool to allow
//you to develop real code and make it think it's using the live data. This
//uses the 'System.Linq' namespace
Mock<IProductRepository> mock = new Mock<IProductRepository>();
mock.Setup(m => m.Products).Returns(new List<Product>
{
new Product { Name = "Football", Price = 25 },
new Product { Name = "Surf board", Price = 179 },
new Product { Name = "Running shoes", Price = 95 }
}.AsQueryable());
ninjectKernel.Bind<IProductRepository>().ToConstant(mock.Object);
}
}
}
In order for a class to access a type declared in another assembly, you must reference them. If you are using Ninject (I suppose), you have did this to the Ninject assembly.
Even though Domain is an assembly of yours, on the same solution, you must reference it at the WebUI, otherwise they won't know each other.
So, let's make sure:
Right click your WebUI project
Select Add reference
Go to Project tab
Select Domain project
Done!
Rebuild and you're good to go!
Regards