AspNETCore Odata Batching - asp.net-core

I'm having some issues trying to configure batching for OData on an AspNETCore Web Application. I've searched everywhere (almost) and couldn't find a proper answer. I'm not sure that the current AspNetCore.Odata version 7.0.0 which is still beta has support for batching.
As far as I am concerned, configuring batching seems impossible now since the MapODataServiceRoute method (from the AspNetCore assemply) doesn't seem to receive any ODataBatchHandler as in .NET common Odata.
app.UseMvc(routes =>
{
routes.Count().Filter().OrderBy().Expand().MaxTop(null);
routes.MapODataServiceRoute("odata", "odata", builder.GetEdmModel()); //Doesn't receive any ODataBatchHandler
routes.EnableDependencyInjection();
});
If someone came across this batching issue for Odata core, some advice would be pretty helpful. Thanks!

Try replace the existing ConfigureServices and Configure methods with the following code:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddOData();
}
public void Configure(IApplicationBuilder app)
{
var builder = new ODataConventionModelBuilder(app.ApplicationServices);
builder.EntitySet<Product>("Products");
app.UseMvc(routeBuilder =>
{
routeBuilder.Select().Expand().Filter().OrderBy().MaxTop(100).Count();
routeBuilder.MapODataServiceRoute("ODataRoute", "odata", builder.GetEdmModel());
routeBuilder.EnableDependencyInjection();
});
}

Related

.NET Core 3.1 - Swagger not loadig

I am trying to implement Swagger in my WebApi. However, it is not working. The issue is that swagger.json loads forever. When I try to go to /swagger/v1/swagger.json, it loads forever and my CPU usages spikes to 100%.
This is my configuration:
public class Startup
{
...
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
...
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo
{
Version = "v1",
Title = "ToDo API"
});
});
...
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider services)
{
...
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
});
// Setup the endpoints.
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller}/{action}/{id?}");
endpoints.MapHub<HomeHub>("/homehub");
});
}
}
I of course already looked around on the internet, but could not find any solution. I do not get any errors, so what could be the issue?
Update:
I have tried generating the json file with the CLI, and same issue. It just loads and nothing happens. Besides taking 24gb of memory...
I believe that one of your controller or class causes this error. It looks like swagger tries to load something recursively.
I suggest you to use memory profiler (like dotMemory) to find out what is going on (what creates this memory leak)
Another workaround is to comment out all your controllers and enable them one by one until you find the erroneous code.
Also you may want to check this Answer

Piranha cms with MySql

I'm trying to use pranha cms (5.3.1) with MySql. This is the code I'm using in my Startup.cs file, but I get this error:
InvalidOperationException: No service for type 'Piranha.IApi' has been registered. What may be the problem?
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc(config =>
{
config.ModelBinderProviders.Insert(0, new Piranha.Manager.Binders.AbstractModelBinderProvider());
});
services.AddPiranhaApplication();
services.AddPiranhaFileStorage();
services.AddPiranhaImageSharp();
services.AddDbContext<Db>(options =>
options.UseMySql("server=localhost;port=3306;database=piranha-mysql;uid=root;password="));
services.AddPiranhaManager();
services.AddPiranhaMemCache();
return services.BuildServiceProvider();
}
Instead of calling AddDbContext you should use:
services.AddPiranhaEF(...);
Which both registers the DbContext and the API that should be used.
Regards

Options<T> not populating in DI

I'm using .Net Core 2.1 and an Aggregate / Facade pattern for my dependencies (which I happily do elsewhere using Ninject / .net 4.6). But when I try to pass through options I get a null (Debugging I can see there being picked up) but there not passed to Autofac (I'm fairly sure its my as they weren't when I tried Ninject either).
I've made a simple test project (new .net core web application /2.1) and then added a minimal amount of code to replicate
Startup.cs
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.Configure<ApiEndpointsConfiguration>(Configuration);
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
// Create the container builder.
var builder = new ContainerBuilder();
builder.Populate(services);
builder.RegisterAggregateService<IViewModelProvider>();
var assemblies = AppDomain.CurrentDomain.GetAssemblies()
.Where(x => x.FullName.StartsWith("TEST")).ToArray();
builder.RegisterAssemblyTypes(assemblies)
.Where(t => t.IsClass)
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
builder.RegisterAggregateService<IDomainServiceProvider>();
ApplicationContainer = builder.Build();
var chkOptions = ApplicationContainer.Resolve<IOptions<ApiEndpointsConfiguration>>();
// Create the IServiceProvider based on the container.
return new AutofacServiceProvider(ApplicationContainer);
}
Program.cs
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureServices(services => services.AddAutofac())
.UseStartup<Startup>();
}
IViewModelProvider.cs
public interface IViewModelProvider
{
IProgrammeViewModelBuilder ProgrammeViewModel { get; }
}
IProgrammeViewModelBuilder.cs
public interface IProgrammeViewModelBuilder
{
ProgrammeViewModel GetProgrammeViewModel();
}
My initial issue was that in my service, controller calls the injected viewmodelbuilder
var viewModel = _viewModels.ProgrammeViewModel.GetProgrammeViewModel();
which in turn calls the service -
readonly IOptions<ApiEndpointsConfiguration> _apiSettings;
public ProgrammeService(IOptions<ApiEndpointsConfiguration> apiSettings) : base (new Uri(apiSettings.Value.BaseAddress))
{
_apiSettings = apiSettings;
}
but at that point (the constructor firing) the service configuration items were null so I've stepped through and I can see that services has the values for "ApiEndpointsConfiguration" picked up but when they get passed through to the "builder" the values are null
ApplicationContainer.Resolve<IOptions<ApiEndpointsConfiguration>>();
shows null for the values inside.
Not sure what it is I'm doing wrong?
:( Truly this is when the answer is so much simpler thank it looks. Kudos to anyone who spots it;
services.Configure<ApiEndpointsConfiguration>(Configuration.GetSection("ApiEndpointsConfiguration"));
rather than
services.Configure<ApiEndpointsConfiguration>(Configuration);
So essentially whilst I thought I could see it debugging I was seeing the raw JSON provided values not the "configured service". I'll leave this here as a lesson to myself to check the simple things first.
Not sure what what was actually being "registered" in my first effort.

How to Implement Minimal Controller

I have an ASP.NET Core 1.1 Web Project.
I have installed Microsoft.OData.Core and followed linked "Getting Started" under http://odata.github.io/.
Both the following Links on that page are for .Net 45
“Build an OData v4 Service with RESTier Library”
“Build an OData v4 Service with OData WebApi Library”
This month old SO answer links to Microsoft.AspNetCore.OData which is NOT owned by Microsoft and was last updated over a year ago.
This SO answer implies "OData Support in ASP.net core"
I see this third party solution AutoODataEF.Core to auto generate controllers however.
Lastly, I see this git issue indicates OData WebAPI for ASP.Net Core is forth coming, but ultimately not currently available.
Assuming I have a Person Model and an EF DbContext.
How do I implement a minimal OData Controller?
odata on asp.net core netcoreapp2.0, 20180216
install-package Microsoft.AspNetCore.OData -Pre {7.0.0-beta1}
in Startup.cs:
public virtual void ConfigureServices(IServiceCollection services)
{
// ...
services.AddMvc(); // mvc first
services.AddOData(); // odata second
}
public virtual void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
// ...
var builder = new ODataConventionModelBuilder(serviceProvider);
builder.EntitySet<SomeClass>(nameof(SomeClass).ToLower()).EntityType.HasKey(s => s.SomeId);
builder.EntitySet<OtherClass>(nameof(OtherClass).ToLower()).EntityType.HasKey(s => s.OtherId).MediaType(); // etc
var model = builder.GetEdmModel();
app.UseMvc(routeBuilder =>
{
routeBuilder.Select().Expand().Filter().OrderBy().MaxTop(null).Count();
routeBuilder.MapODataServiceRoute("ODataRoute", "data", model); // e.g. http://localhost:port/data/someclass?...
// insert special bits for e.g. custom MLE here
routeBuilder.EnableDependencyInjection();
routeBuilder.MapRoute(name: "default", template: "{controller=Home}/{action=Index}/{id?}"); // enable mvc controllers
});
}
in SomeClassController.cs:
public class SomeClassController : ODataController // or just plain Controller
{
[EnableQuery]
[HttpGet]
[ODataRoute("someclass")]
public List<SomeClass> Get() // this should maybe be an IQueryable wrapped by an IActionResult/OkObjectResult
{
List<SomeClass> list = new List<SomeClass>();
// however you do this
return list;
}
}

Alternative to 'Session_Start' in MVC 6

I'am trying to rewrite an old e-shop to MVC 6, and I'am solving a lot of problems. One of it is that I need to set up some default data when session is beginning. I found nothing usable for thins in MVC 6.
I have multiple shops implemented as one application, and I need to set for example a ShopID when session is starting. Setting is by IP address. This is not the only thing I'am setting there, but its one of the most descriptive things.
Do you have some idea how to implement this, or advice how to do it in different way ?
Sample code from old implementation in global.asax:
void Session_Start(object sender, EventArgs e)
{
string url = Request.Url.Host;
switch (url)
{
case "127.0.0.207":
(SomeSessionObject)Session["SessionData"].ShopID = 123;
break;
case "127.0.0.210":
(SomeSessionObject)Session["SessionData"].ShopID = 345;
break;
}
}
This code i would like to write down somehow in MVC 6, but have no idea where to place it, or even if it is possible.
Following is probably one way of achieving what you are trying to do...Here I am registering a middleware right after the Session middleware so that when a request comes in it would be intercepted by this middleware after Session middleware does its work. You can try it and see if it suits your scenario.
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Http;
using Microsoft.Framework.DependencyInjection;
namespace WebApplication43
{
public class Startup
{
// This method gets called by a runtime.
// Use this method to add services to the container
public void ConfigureServices(IServiceCollection services)
{
services.AddCaching();
services.AddSession();
services.AddMvc();
}
// Configure is called after ConfigureServices is called.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseStaticFiles();
app.UseSession();
app.Use((httpContext, nextMiddleware) =>
{
httpContext.Session.SetInt32("key1", 10);
httpContext.Session.SetString("key2", "blah");
return nextMiddleware();
});
app.UseMvc();
}
}
}
Related package dependencies in project.json:
"dependencies": {
"Microsoft.AspNet.Mvc": "6.0.0-beta7",
"Microsoft.AspNet.StaticFiles": "1.0.0-beta7",
"Microsoft.AspNet.Session": "1.0.0-beta7",
"Microsoft.Framework.Caching.Memory": "1.0.0-beta7",
"Microsoft.AspNet.Http.Extensions": "1.0.0-beta7",