ServiceStack Service which has a Stream in its request breaks metadata page - c#

When I create a simple ServiceStack service with a Stream in the request, I find that I am unable to access the metadata page for the service method.
The service itself appears to work (I can send a stream to http://localhost:12345/uploadStream using PostMan and I can deserialize the stream in the service method OK with a bit of extra code.)
I am using .NET Core and Servicestack...
Complete repo:
using Funq;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using ServiceStack;
using ServiceStack.Web;
using System;
using System.IO;
using System.Threading.Tasks;
namespace ServiceStackCoreTest
{
class Program
{
static void Main(string[] args)
{
IWebHost host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.UseUrls("http://*:12345/test/")
.Build();
host.Run();
}
}
public class Startup
{
public void ConfigureServices(IServiceCollection services){ }
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.ApplicationServices.GetService<ILoggerFactory>();
app.UseServiceStack((AppHostBase)Activator.CreateInstance<AppHost>());
app.Run((RequestDelegate)(context => (Task)Task.FromResult<int>(0)));
}
}
public class AppHost : AppHostBase
{
public AppHost() : base("Test Service", typeof(Program).GetAssembly()){ }
public override void Configure(Container container){ }
}
public class MyService : Service
{
public TestResponse Any(TestRequest request)
{
return new TestResponse();
}
}
[Route("/uploadStream", "POST", Summary = "Upload stream")]
public class TestRequest : IReturn<TestResponse>, IRequiresRequestStream
{
public Stream RequestStream { get; set; }
}
public class TestResponse{ }
}
My complete csproj (I am using Windows 10 / VS2017)...
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp1.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="1.1.1" />
<PackageReference Include="ServiceStack.Core" Version="1.0.40" />
<PackageReference Include="ServiceStack.Kestrel" Version="1.0.40" />
</ItemGroup>
</Project>
When I browse to the metadata page, I can see the list of operations, but when I click on 'XML', 'JSON' or 'JSV' next to the 'TestRequest' method, I get an error ERR_INCOMPLETE_CHUNKED_ENCODING in chrome (Edge reports nothing), and in my output window, I see Exception thrown: 'System.MemberAccessException' in System.Private.CoreLib.ni.dll. Oddly enough, clicking on 'CSV' gives me a metadata page.
Am I creating the service method incorrectly in my ServiceStack project?

The .NET Core package had an issue where wasn't able to create an instance of an abstract class (Stream) which should now be resolved from this commit.
This change is available from v1.0.41 *.Core packages that are now available on NuGet.

Related

How to configure a default JsonSerializerOptions (System.Text.Json) to be used by Azure Function v3?

I have a set of Azure Functions v3 running on .net core 3.1.
I have a custom configuration of JsonSerializerOptions that I want to be used automatically by my functions when de/serializing data.
Question
How can I set up my Azure Functions so that they can use my default System.Text.Json.JsonSerializerOptions instance?
Update 1
Following the suggestion from #sellotape, I found out the following documentation regarding the JsonResult class:
The problem is that my JsonResult instance does not have this property of type object ; it is only accepting a JsonSerializerSettings instance.
Update 2
I still get the following error and I am not sure where Newtonsoft is coming from:
Microsoft.AspNetCore.Mvc.NewtonsoftJson: Property 'JsonResult.SerializerSettings' must be an instance of type 'Newtonsoft.Json.JsonSerializerSettings'.
It's not a perfect solution for those with existing Azure Function apps, but the Azure Functions for .net 5 isolated runtime allows you to configure the JSON serialization options now. So for anyone starting new azure functions or have the budget and energy to upgrade existing ones, there's now first-class support for configuring the serializer exactly how you like it. It's unfortunate that enums have been second class citizens until just now, but better late than never.
Program.cs
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.DependencyInjection;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace MyFunctionApp
{
public class Program
{
public static void Main()
{
var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults()
.ConfigureServices(services =>
{
services.Configure<JsonSerializerOptions>(options =>
{
options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
options.Converters.Add(new JsonStringEnumConverter());
});
})
.Build();
host.Run();
}
}
}
If you want to pick System.Text.Json or Newtonsoft.Json there you could configure either one like seen in this example
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
using System.Text.Json;
using System.Text.Json.Serialization;
using Azure.Core.Serialization;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
namespace Configuration
{
public class Program
{
public static void Main()
{
var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults(workerApplication =>
{
// Use any of the extension methods in WorkerConfigurationExtensions.
})
.Build();
host.Run();
}
}
internal static class WorkerConfigurationExtensions
{
/// <summary>
/// Calling ConfigureFunctionsWorkerDefaults() configures the Functions Worker to use System.Text.Json for all JSON
/// serialization and sets JsonSerializerOptions.PropertyNameCaseInsensitive = true;
/// This method uses DI to modify the JsonSerializerOptions. Call /api/HttpFunction to see the changes.
/// </summary>
public static IFunctionsWorkerApplicationBuilder ConfigureSystemTextJson(this IFunctionsWorkerApplicationBuilder builder)
{
builder.Services.Configure<JsonSerializerOptions>(jsonSerializerOptions =>
{
jsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
jsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
jsonSerializerOptions.ReferenceHandler = ReferenceHandler.Preserve;
// override the default value
jsonSerializerOptions.PropertyNameCaseInsensitive = false;
});
return builder;
}
/// <summary>
/// The functions worker uses the Azure SDK's ObjectSerializer to abstract away all JSON serialization. This allows you to
/// swap out the default System.Text.Json implementation for the Newtonsoft.Json implementation.
/// To do so, add the Microsoft.Azure.Core.NewtonsoftJson nuget package and then update the WorkerOptions.Serializer property.
/// This method updates the Serializer to use Newtonsoft.Json. Call /api/HttpFunction to see the changes.
/// </summary>
public static IFunctionsWorkerApplicationBuilder UseNewtonsoftJson(this IFunctionsWorkerApplicationBuilder builder)
{
builder.Services.Configure<WorkerOptions>(workerOptions =>
{
var settings = NewtonsoftJsonObjectSerializer.CreateJsonSerializerSettings();
settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
settings.NullValueHandling = NullValueHandling.Ignore;
workerOptions.Serializer = new NewtonsoftJsonObjectSerializer(settings);
});
return builder;
}
}
}
Turns out I missed a step when upgrading my Azure Functions from v2 to v3. To make it work, I had to add the Microsoft.AspNetCore.App framework to my csproj. Otherwise, my project kept referencing JsonResult from Microsoft.Aspnet.Mvc.Core v2.X.X which does not support System.Text.Json.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework>
</PropertyGroup>
<!-- ADD THESE LINES -->
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
</Project>
Then, I was able to specify my own JsonSerializerOptions instance like this:
return new JsonResult(<ContractClass>, NSJsonSerializerOptions.Default)
{
StatusCode = StatusCodes.Status200OK
};
where NSJsonSerializerOptions.Default is a static instance of JsonSerializerOptions.

ASP.NET Core console app cannot find controllers

I have created a simple .NET Core console project that includes ASP.NET core, as below:
MyProject.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.1" />
</ItemGroup>
</Project>
And in my Program.cs:
public class Program
{
static void Main()
{
WebHost.CreateDefaultBuilder()
.UseKestrel()
.UseStartup<Startup>()
.UseUrls("http://localhost:1234")
.Build()
.Run();
}
}
In my Startup.cs I have:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvc();
}
}
And a single controller in a Controllers folder:
public class HomeController : Controller
{
[Route("Home/Index")]
public IActionResult Index()
{
return Ok("Hello from index");
}
}
But nothing I can do seems to make it hit my controller.
The logs are showing that requests to http://localhost:1234/Home/Index are coming through Kestrel, but 404ing.
What am I missing? I have also tried specifying routes, but have had no luck in making it find the controller.
I’m not sure if this is the reason why but your kestrel is using the old 1.1 version, in order for certain process to run properly such as migrations, which relies on duck typing you should declare a BuildWebHost method:
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
}
There’s more information in the docs. If this doesn’t work I would create a new project and move things across manually. The only other issue I could think of would be your package manager cache is messed up or you have too many run times installed on your machine
Remove:
.UseUrls("http://localhost:1234")
That could be as a result of separate URLs in the launchSettings.json
Afterwards add the routing and endpoints to the middleware,
app.UseRouting();
app.UseEndpoints(e =>
e.MapControllerRoute( name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}")
);
Also, register the mvc service
services.AddMvc();

Routing is not working with self-hosted web API [duplicate]

This question already has an answer here:
WebApi giving 404 whilst debugging; works when published
(1 answer)
Closed 3 years ago.
This is essentially what I have, a very simple set of three files with fresh asp.net core 2.1 (actually copy-pasted from tutorials):
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
}
Then goes the simplest startup
class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseMvc();
}
}
And default values controller
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
return new string[] { "value1", "value2" };
}
}
No matter what I call I see in console same 404 error:
Application started. Press Ctrl+C to shut down.
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://localhost:5000/values
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 105.0181ms 404
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://localhost:5000/api/values
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 2.6016ms 404
etc
I tried adding default route both with app.UseMvcWithDefaultRoute(); and specifying it manually. I tried removing route attributes when used the default route. Also tried adding AddControllersAsServices(). But result is still same - 404. When I setup custom handler in app.Run then it works without any issues.
csproj (I have replaced default Microsoft.AspNetCore.All dependency, but routing still does not work)
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.0" />
</ItemGroup>
</Project>
This was rather difficult to track down, but the problem boils down to this in your .csproj:
<Project Sdk="Microsoft.NET.Sdk">
As you are building a web application, you need to instead reference the Web Sdk, as follows:
<Project Sdk="Microsoft.NET.Sdk.Web">
I managed to reproduce and fix your issue with this small change.
For me it helped adding AddApplicationPart after AddMvc like this:
.AddMvc()
.AddApplicationPart(typeof(Startup).Assembly)
you can try change code to this:
[ApiController]
public class ValuesController : ControllerBase
{
[HttpGet]
[Route("api/values")]
public ActionResult<IEnumerable<string>> Get()
{
return new string[] { "value1", "value2" };
}
}
The atribute Route can use for asigning an specific route to a function on api or view.
then to call you can use:
'localhost:5000/api/values'

Add an implementation of 'IDesignTimeDbContextFactory<ServicesDbContext>' to the project error while creating a migration step in .NET core 2.0

I had a .NET core 1.0 webapp working fine. I had to upgrade to .NET Core 2.0. I also had to add a migration step for my SQLite database.
If I launch this command:
Add-Migration MyMigrationStepName
I get this error:
Unable to create an object of type 'ServicesDbContext'. Add an
implementation of 'IDesignTimeDbContextFactory' to
the project, or see https://go.microsoft.com/fwlink/?linkid=851728 for
additional patterns supported at design time.
I've seen plenty of answers on SO and on other blogs and website but none of them actually say where to implement such interface and what code the concrete method should contain!
Sample:
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { }
}
public class ApplicationContextDbFactory : IDesignTimeDbContextFactory<ApplicationDbContext>
{
ApplicationDbContext IDesignTimeDbContextFactory<ApplicationDbContext>.CreateDbContext(string[] args)
{
var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
optionsBuilder.UseSqlServer<ApplicationDbContext>("Server = (localdb)\\mssqllocaldb; Database = MyDatabaseName; Trusted_Connection = True; MultipleActiveResultSets = true");
return new ApplicationDbContext(optionsBuilder.Options);
}
}
Location:
Put that class where the ApplicationDbContext is put. It will then be automatically picked up when you use dotnet ef cli commands.
A possible solution to IDesignTimeDbContextFactory<> problem is the DBContext discovery/launch during the add-migration process.
Add migrations needs to get a context. If it cant, this error is thrown.
This can happen if you do not have a public parameter-less DBContext.
So a solution is to Add a public Parameter-less constructor to your context.
public class SomeDbContext: DbContext
{
// this PUBLIC constructor is required for Migration tool
public SomeDbContext()
{
}
// the model...
public DbSet<PocoBla> PocoBlas { get; set; }
....
}
You can have a special version of your DBContext in a separate project .netCore console project for migration code generation purposes.
I solve the problem by simply updating Program.cs to the latest .NET Core 2.x pattern:
From 1.x:
using System.IO; using Microsoft.AspNetCore.Hosting;
namespace AspNetCoreDotNetCore1App {
public class Program
{
public static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.UseApplicationInsights()
.Build();
host.Run();
}
} }
To 2.x:
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
namespace AspNetCoreDotNetCore2App
{
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
}
}
Source: https://learn.microsoft.com/en-us/ef/core/miscellaneous/cli/dbcontext-creation

dotnet core no overload method for UseInMemoryDatabase() takes 0 argument

I am trying dotnet core tutorial at https://learn.microsoft.com/en-us/aspnet/core/tutorials/web-api-vsc
TodoContext.cs
using Microsoft.EntityFrameworkCore;
namespace TodoApi.Models
{
public class TodoContext : DbContext
{
public TodoContext(DbContextOptions<TodoContext> options)
: base(options)
{
}
public DbSet<TodoItem> TodoItems { get; set; }
}
}
Startup.cs
using ...
using TodoApi.Models;
using Microsoft.EntityFrameworkCore;
namespace TodoApi
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<TodoContext>(opt => opt.UseInMemoryDatabase());
services.AddMvc();
services.AddScoped<ITodoRepository, TodoRepository>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseMvc();
}
}
}
So I got this "no overload method for UseInMemoryDatabase() takes 0 argument"
I googled for UseInMemoryDatabase() method signature but could not find any.
What arguments should I provide to UseInMemoryDatabase()?
Update:
Once I downgrade Microsoft.EntityFrameworkCore.InMemory from 2.0.0-preview1-final to 1.1.1 and ran dotnet restore the error disappeared.
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0-preview1-final"/>
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="1.1.1"/>
</ItemGroup>
I suspect the error is due to there is no "2.0.0-preview1-final" for Microsoft.EntityFrameworkCore.InMemory? If this is true then the error is not because of the number of argument but because InMemory db was is not installed and therefore UseInMemoryDatabase() was not defined anywhere in the project.
You need to give Database name.
services.AddDbContext<ApiContext>(options => options.UseInMemoryDatabase("RazorPagesApp"));
Install-Package Microsoft.EntityFrameworkCore.InMemory
This solved my problem

Categories

Resources