Apologies for the long text!
I'm trying to build a message listener for RabbitMQ in aspnet core 2.1. As soon as I post a message, I get this error in the log:
2018-09-29 12:35:35.459 INFO NServiceBus.RecoverabilityExecutor
Immediate Retry is going to retry message 'ab43' because of an
exception:
System.InvalidOperationException: Unable to resolve type:
Event.Processor.Listener.CustomerReceivedHandler, service name: --->
System.InvalidOperationException: Unresolved dependency
csproj:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<AssemblyName>Event.Processor</AssemblyName>
<RootNamespace>Event.Processor</RootNamespace>
</PropertyGroup>
<ItemGroup>
<Folder Include="wwwroot\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Customer.Models" Version="1.0.21875" />
<PackageReference Include="lightinject" Version="5.2.0" />
<PackageReference Include="LightInject.Microsoft.DependencyInjection" Version="2.0.8" />
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="nservicebus" Version="7.1.4" />
<PackageReference Include="NServiceBus.RabbitMQ" Version="5.0.1" />
<PackageReference Include="odp.netcore" Version="2.0.12" />
<PackageReference Include="serilog" Version="2.7.1" />
<PackageReference Include="Serilog.aspnetcore" Version="2.1.1" />
<PackageReference Include="serilog.settings.configuration" Version="2.6.1" />
<PackageReference Include="serilog.sinks.console" Version="3.1.1" />
<PackageReference Include="serilog.sinks.file" Version="4.0.0" />
</ItemGroup>
<ItemGroup>
<Content Update="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project>
Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvc();
app.Run(async context =>
{
await context.Response.WriteAsync("Hello Processor");
});
}
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc();
ServiceContainer container = new ServiceContainer(new ContainerOptions
{
EnablePropertyInjection = false
});
//The below didn't work either!
//services.AddSingleton<IDbProvider, DbProvider>();
//services.AddSingleton<IConfigSettings, ConfigSettings>();
//services.AddSingleton<IEncryptor, Encryptor>();
container.Register<IDbProvider, DbProvider>();
container.Register<IConfigSettings, ConfigSettings>();
container.Register<IEncryptor, Encryptor>();
return container.CreateServiceProvider(services);
}
}
Program.cs
public class Program
{
public static void Main(string[] args)
try
{
var endpointConfiguration = new EndpointConfiguration("MSG_QUEUE");
var transport = endpointConfiguration.UseTransport<RabbitMQTransport>();
transport.UseConventionalRoutingTopology();
transport.ConnectionString("ConxnString");
endpointConfiguration.EnableInstallers();
endpointConfiguration.SendFailedMessagesTo("error");
endpointConfiguration.AutoSubscribe();
endpointConfiguration.UsePersistence<InMemoryPersistence>();
endpointConfiguration.UseSerialization<XmlSerializer>();
Endpoint.Start(endpointConfiguration).GetAwaiter().GetResult();
//IEndpointInstance endpointInstance = Endpoint.Start(endpointConfiguration).GetAwaiter().GetResult();
//endpointInstance.Stop().ConfigureAwait(false);
//Log.Information("Starting web host");
CreateWebHostBuilder(args).Build().Run();
}
catch (Exception ex)
{
//Log.Fatal(ex, "Host terminated unexpectedly");
}
finally
{
//Log.CloseAndFlush();
}
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
}
MessageHandler.cs
public class CustomerReceivedHandler : IHandleMessages<PubSubObject>
{
private readonly IDbProvider _DbProvider;
private static readonly ILog Log = LogManager.GetLogger<CustomerReceivedHandler>();
public CustomerReceivedHandler(IDbProvider DbProvider)
{
_DbProvider = DbProvider;
// If I don't inject and initialize as below, it works fine
//_DbProvider = new DbProvider(new ConfigSettings(new Encryptor());
}
public Task Handle(PubSubObject message, IMessageHandlerContext context)
{
Log.Info($"Received message with id {context.MessageId}");
}
}
Apparently I should've used the below code:
endpointConfiguration.UseContainer<ServicesBuilder>(
customizations: customizations =>
{
customizations.ExistingServices(services);
});
Working after I followed: https://docs.particular.net/samples/dependency-injection/aspnetcore/
Related
I added healthcheck to asp.net core application. When healthcheck is fail - return "Unhealthy", but I can't get any information why it failed. There is no logs - in console, in logger with file. How can i see the error, exception?
I simplified the code for .net6 webapplication
Programm.cs
using WebApi6HealthCheck;
using Microsoft.EntityFrameworkCore;
using Serilog;
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseSerilog((ctx, lc) => lc
.WriteTo.Console());
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddDbContext<OneProfileContext>(opt =>
opt.UseSqlServer("Data Source=fake-dbsql-S2016;Initial Catalog=S7OneProfile;User Id=kos_debugger;Password=SecretPassword;Connect Timeout=3;"));
builder.Services.AddHealthChecks()
.AddDbContextCheck<OneProfileContext>(tags: new[] { "live" });
var app = builder.Build();
app.UseHttpsRedirection();
app.MapControllers();
app.MapHealthChecks("/health/live", new HealthCheckOptions()
{
Predicate = (check) => check.Tags.Contains("live")
});
app.Run();
There is no datebase and healthcheck for dbcontext will fail.
In console I see this image
References
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="6.0.1" />
<PackageReference Include="Serilog.AspNetCore" Version="4.1.0" />
UPDATE
If i call dbContext from controller method i see exception in console - and this is right,good,fan. But I want see same exception when call HealthCheck - /health/live
WeatherForecastController.cs
using Microsoft.AspNetCore.Mvc;
namespace WebApi6HealthCheck.Controllers
{
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private readonly ILogger<WeatherForecastController> _logger;
private readonly OneProfileContext _dbContext;
public WeatherForecastController(ILogger<WeatherForecastController> logger, OneProfileContext dbContext)
{
_logger = logger;
_dbContext = dbContext;
}
[HttpGet(Name = "GetWeatherForecast")]
public string Get()
{
var appEvent=_dbContext.ApplicationEvents.FirstOrDefault();
return "Hello,world";
}
}
}
GET https://localhost:7197/WeatherForecast
My suggestion is below: add logs on Console with .NET Core and Serilog
1.Install the Serilog, Serilog.AspNetCore, and Serilog.Extensions.Logging NuGet packages to integrate the basic functionalities of Serilog.
2.Download the Serilog.Sinks.Console and Serilog.Sinks.Async NuGet packages to use the Console as a destination of your logs.
3.Update the Program class to specify that the application must use Serilog.
Log.Logger = new LoggerConfiguration().CreateLogger();
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseSerilog((hostingContext, loggerConfiguration) =>
loggerConfiguration.ReadFrom.Configuration(hostingContext.Configuration));
4.Use ILogger<T> instead of Serilog.ILogger
Since we have bound the Serilog logger to the one native on .NET - the one coming from Microsoft.Extensions.Logging - we can use the native logger everywhere in the project.
Add a dependency to ILogger<T> in your constructor, where T is the name of the class itself:
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
public IActionResult Index()
{
_logger.LogInformation("Getting random items. There are {AvailableItems} possible values");
_logger.LogWarning("This is a warning");
try
{
throw new ArgumentException();//you can modify codes to catch your health-check
}
catch (Exception ex)
{
_logger.LogError(ex, "And this is an error");
}
return View();
}
}
5.Define the settings in the appsettings.json file instead of directly in the code
{
"Serilog": {
"Using": [ "Serilog.Sinks.Console" ],
"MinimumLevel": {
"Default": "Verbose",
"Override": {
"Microsoft": "Warning",
"Microsoft.AspNetCore": "Warning",
"System": "Error"
}
},
"WriteTo": [
{
"Name": "Async",
"Args": {
"configure": [
{
"Name": "Console",
"Args": {
"theme": "Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme::Code, Serilog.Sinks.Console",
"formatter": "Serilog.Formatting.Compact.RenderedCompactJsonFormatter, Serilog.Formatting.Compact"
}
}
]
}
}
]
},
"AllowedHosts": "*"
}
Result:
I find a link,hoping it can help you.
I have a clean .net 5 api project that will always redirect(307) to https for some reason when accessing the site thew iis 10. The site didn't have https enabled when it was created. The only thing special about the setup is that the site in iis uses a custom domain (api.projectname.dev) defined in the host file that points to 127.0.0.1. The the api doesn't redirect if I run it using iis express using visual studio. And the default iis site doesn't redirect to https. Does anyone know what might be the cause of this?
Program.cs
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
Startup.cs
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.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "project.Api", Version = "v1" });
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "project.Api v1"));
}
app.UseRouting();
//app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
web.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<location path="." inheritInChildApplications="false">
<system.webServer>
<handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
</handlers>
<aspNetCore processPath="bin\Debug\net5.0\project.Api.exe" arguments="" stdoutLogEnabled="false" hostingModel="InProcess">
<environmentVariables>
<environmentVariable name="ASPNETCORE_ENVIRONMENT" value="Development" />
</environmentVariables>
</aspNetCore>
</system.webServer>
</location>
</configuration>
Remove the line UseHttpsRedirection() from your Program or Startup.cs
I'am try to authenticate client mvc application using identity server.
my application have Identity server mvc application , MVC application, API
I 'am used 4 scoped in client MVC application (OpenId,email,profile,office-- office is Custom claim type).
i'am use this code to create identity server with authenticate mvc application .
1 identity server run
2 MVC application run
3 Login link click using MVC application
Image1
4 Login the identity server using TestUser details
Image2
5 after login success always display this screen (not show my all scope to check in client application)
Image3
Identity Server - (http://localhost:61632)
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.AddMvc();
services.AddIdentityServer()
.AddTestUsers(TestUsers.Users)
.AddInMemoryClients(Config.GetClients())
.AddInMemoryIdentityResources(Config.GetIdentityResources())
.AddInMemoryApiResources(Config.GetApiResources());
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseBrowserLink();
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseIdentityServer();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
TestUser class
public class TestUsers
{
public static List<TestUser> Users = new List<TestUser>
{
new TestUser{SubjectId = "818727", Username = "Kasunjith", Password = "kasunjith",
Claims =
{
new Claim("office_Id","23"),
new Claim(JwtClaimTypes.Name, "Alice Smith"),
new Claim(JwtClaimTypes.GivenName, "Alice"),
new Claim(JwtClaimTypes.FamilyName, "Smith"),
new Claim(JwtClaimTypes.Email, "AliceSmith#email.com"),
new Claim(JwtClaimTypes.EmailVerified, "true", ClaimValueTypes.Boolean),
new Claim(JwtClaimTypes.WebSite, "http://alice.com"),
new Claim(JwtClaimTypes.Address, #"{ 'street_address': 'One Hacker Way', 'locality': 'Heidelberg', 'postal_code': 69118, 'country': 'Germany' }", IdentityServer4.IdentityServerConstants.ClaimValueTypes.Json)
}
},
new TestUser{SubjectId = "88421113", Username = "bimal", Password = "bimal",
Claims =
{
new Claim("office_Id","24"),
new Claim(JwtClaimTypes.Name, "Bob Smith"),
new Claim(JwtClaimTypes.GivenName, "Bob"),
new Claim(JwtClaimTypes.FamilyName, "Smith"),
new Claim(JwtClaimTypes.Email, "BobSmith#email.com"),
new Claim(JwtClaimTypes.EmailVerified, "true", ClaimValueTypes.Boolean),
new Claim(JwtClaimTypes.WebSite, "http://bob.com"),
new Claim(JwtClaimTypes.Address, #"{ 'street_address': 'One Hacker Way', 'locality': 'Heidelberg', 'postal_code': 69118, 'country': 'Germany' }", IdentityServer4.IdentityServerConstants.ClaimValueTypes.Json),
new Claim("location", "somewhere")
}
}
};
}
Config class
public class Config
{
public static IEnumerable<Client> GetClients()
{
return new Client[]
{
new Client
{
ClientId ="mvc",
ClientName="MVC Demo",
AllowedGrantTypes = GrantTypes.Implicit,
RedirectUris ={ "http://localhost:62104/signin-oidc" },
AllowedScopes={ "openid","email", "profile","office"},
AllowRememberConsent = true,
}
};
}
public static IEnumerable<IdentityResource> GetIdentityResources()
{
return new IdentityResource[]
{
new IdentityResources.OpenId(),
new IdentityResources.Email(),
new IdentityResources.Profile(),
new IdentityResource
{
Name="office",
DisplayName ="office details",
UserClaims = {"office_Id"}
}
};
}
public static IEnumerable<ApiResource> GetApiResources()
{
return new ApiResource[]
{
};
}
}
Client - Mvc application ( http://localhost:62104)
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.AddMvc();
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
//options.DefaultAuthenticateScheme = "Cookies";
}).AddCookie("Cookies")
.AddOpenIdConnect("oidc", options =>
{
options.SignInScheme = "Cookies";
options.RequireHttpsMetadata = false;
options.Authority = "http://localhost:61632";
options.ClientId = "mvc";
options.ResponseType = "id_token";
//options.CallbackPath = new PathString("...")
//options.SignedOutCallbackPath = new PathString("...")
options.Scope.Add("openid");
options.Scope.Add("email");
options.Scope.Add("profile");
options.Scope.Add("office");
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseBrowserLink();
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseAuthentication();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
Found the issue (this was hard!)
The code works just fine. The part that does not work is displaying the scopes in the Consent View. The problem boils down to this line:
Views/Consent/Index.cshtml
<partial name="_ScopeListItem" model="#scope" />
This uses the Partial Tag Helper, introduced in ASP.NET 2.1.
The project you linked in the comments (your project) uses ASP.NET 2.0, but the QuickStart UI you copied from IdentityServer uses ASP.NET Core 2.1 so basically, they are incompatible. To fix, either use the proper Tag helper for your version or (I recommend) upgrade to ASP.NET Core 2.2. For that you can:
Change the project file:
<Project Sdk="Microsoft.NET.Sdk.Web">
<!-- Upgrade the project to .NET Core 2.2-->
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="IdentityServer4" Version="2.3.2" />
<!-- Change the ASP.NET Core from All to App. -->
<PackageReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
<ItemGroup>
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.2" />
</ItemGroup>
</Project>
And the Startup.cs
public IConfiguration Configuration { get; }
public IHostingEnvironment Environment { get; }
public Startup(IConfiguration configuration, IHostingEnvironment environment)
{
Configuration = configuration;
Environment = environment;
}
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(Microsoft.AspNetCore.Mvc.CompatibilityVersion.Version_2_1);
var builder = services.AddIdentityServer()
.AddTestUsers(TestUsers.Users)
.AddInMemoryClients(Config.GetClients())
.AddInMemoryIdentityResources(Config.GetIdentityResources())
.AddInMemoryApiResources(Config.GetApiResources());
// without this you can't sign jwt tokens in dev. still need to configure for prod.
if (Environment.IsDevelopment())
{
builder.AddDeveloperSigningCredential();
}
else
{
throw new Exception("need to configure key material");
}
}
Since you are into it, I'd also suggest upgrading the MVC (client) app as well. I sent a PR on your GitHub repo that has the changes mentioned above plus a view to listing the scopes/claims after your user is logged in.
I'm getting an error when using $filter with $apply=groupby. It appears to happen only when the filter field is not in the groupby expression. Here is the error message:
Instance property 'DRG_Definition' is not defined for type 'DynamicTypeWrapper'
This works fine:
http://localhost:9810/odata/PAYMENTS?$apply=groupby((Provider_Id,DRG_Definition),aggregate(Total_Payments with sum as Total_Payments))&$filter=(DRG_Definition eq '069 - TRANSIENT ISCHEMIA')
This throws the error (only difference is no DRG_Definition field in the groupby):
http://localhost:9810/odata/PAYMENTS?$apply=groupby((Provider_Id),aggregate(Total_Payments with sum as Total_Payments))&$filter=(DRG_Definition eq '069 - TRANSIENT ISCHEMIA')
Updated with my packages and code samples below:
<packages>
<package id="EntityFramework" version="6.1.3" targetFramework="net452" />
<package id="Microsoft.ApplicationInsights" version="2.1.0" targetFramework="net452" />
<package id="Microsoft.ApplicationInsights.Agent.Intercept" version="1.2.1" targetFramework="net452" />
<package id="Microsoft.ApplicationInsights.DependencyCollector" version="2.1.0" targetFramework="net452" />
<package id="Microsoft.ApplicationInsights.JavaScript" version="0.15.0-build58334" targetFramework="net452" />
<package id="Microsoft.ApplicationInsights.PerfCounterCollector" version="2.1.0" targetFramework="net452" />
<package id="Microsoft.ApplicationInsights.Web" version="2.1.0" targetFramework="net452" />
<package id="Microsoft.ApplicationInsights.WindowsServer" version="2.1.0" targetFramework="net452" />
<package id="Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel" version="2.1.0" targetFramework="net452" />
<package id="Microsoft.AspNet.OData" version="5.9.1" targetFramework="net452" />
<package id="Microsoft.AspNet.WebApi" version="5.2.3" targetFramework="net452" />
<package id="Microsoft.AspNet.WebApi.Client" version="5.2.3" targetFramework="net452" />
<package id="Microsoft.AspNet.WebApi.Core" version="5.2.3" targetFramework="net452" />
<package id="Microsoft.AspNet.WebApi.WebHost" version="5.2.3" targetFramework="net452" />
<package id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" version="1.0.1" targetFramework="net452" />
<package id="Microsoft.Net.Compilers" version="1.3.2" targetFramework="net452" developmentDependency="true" />
<package id="Microsoft.OData.Core" version="6.15.0" targetFramework="net452" />
<package id="Microsoft.OData.Edm" version="6.15.0" targetFramework="net452" />
<package id="Microsoft.Spatial" version="6.15.0" targetFramework="net452" />
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net452" />
<package id="System.Spatial" version="5.7.0" targetFramework="net452" />
</packages>
Here's the WebApiConfig.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
using System.Web.OData.Builder;
using System.Web.OData.Extensions;
using HealthcareWebApp;
namespace HealthcareWebApp
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
//Custom code
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<PAYMENTS>("PAYMENTS"); //.EntityType.HasKey(p => p.PAYMENT_KEY);
builder.EntitySet<DATE_DIM>("DATE_DIM"); //.EntityType.HasKey(p => p.Year);
builder.EntitySet<PROVIDERS>("PROVIDERS"); //.EntityType.HasKey(p => p.Provider_Id);
config.MapODataServiceRoute("odata", "odata", builder.GetEdmModel());
}
}
}
PAYMENTSController.cs:
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.ModelBinding;
using System.Web.OData;
using System.Web.OData.Query;
using System.Web.OData.Routing;
using HealthcareWebApp;
namespace HealthcareWebApp.Controllers
{
/*
The WebApiConfig class may require additional changes to add a route for this controller. Merge these statements into the Register method of the WebApiConfig class as applicable. Note that OData URLs are case sensitive.
using System.Web.OData.Builder;
using System.Web.OData.Extensions;
using HealthcareWebApp;
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<PAYMENTS>("PAYMENTS");
builder.EntitySet<DATE_DIM>("DATE_DIM");
builder.EntitySet<PROVIDERS>("PROVIDERS");
config.MapODataServiceRoute("odata", "odata", builder.GetEdmModel());
*/
public class PAYMENTSController : ODataController
{
private FlexIT_HealthcareEntities db = new FlexIT_HealthcareEntities();
// GET: odata/PAYMENTS
[EnableQuery]
public IQueryable<PAYMENTS> GetPAYMENTS()
{
return db.PAYMENTS;
}
// GET: odata/PAYMENTS(5)
[EnableQuery]
public SingleResult<PAYMENTS> GetPAYMENTS([FromODataUri] int key)
{
return SingleResult.Create(db.PAYMENTS.Where(pAYMENTS => pAYMENTS.PAYMENT_KEY == key));
}
// PUT: odata/PAYMENTS(5)
public IHttpActionResult Put([FromODataUri] int key, Delta<PAYMENTS> patch)
{
Validate(patch.GetEntity());
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
PAYMENTS pAYMENTS = db.PAYMENTS.Find(key);
if (pAYMENTS == null)
{
return NotFound();
}
patch.Put(pAYMENTS);
try
{
db.SaveChanges();
}
catch (DbUpdateConcurrencyException)
{
if (!PAYMENTSExists(key))
{
return NotFound();
}
else
{
throw;
}
}
return Updated(pAYMENTS);
}
// POST: odata/PAYMENTS
public IHttpActionResult Post(PAYMENTS pAYMENTS)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.PAYMENTS.Add(pAYMENTS);
db.SaveChanges();
return Created(pAYMENTS);
}
// PATCH: odata/PAYMENTS(5)
[AcceptVerbs("PATCH", "MERGE")]
public IHttpActionResult Patch([FromODataUri] int key, Delta<PAYMENTS> patch)
{
Validate(patch.GetEntity());
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
PAYMENTS pAYMENTS = db.PAYMENTS.Find(key);
if (pAYMENTS == null)
{
return NotFound();
}
patch.Patch(pAYMENTS);
try
{
db.SaveChanges();
}
catch (DbUpdateConcurrencyException)
{
if (!PAYMENTSExists(key))
{
return NotFound();
}
else
{
throw;
}
}
return Updated(pAYMENTS);
}
// DELETE: odata/PAYMENTS(5)
public IHttpActionResult Delete([FromODataUri] int key)
{
PAYMENTS pAYMENTS = db.PAYMENTS.Find(key);
if (pAYMENTS == null)
{
return NotFound();
}
db.PAYMENTS.Remove(pAYMENTS);
db.SaveChanges();
return StatusCode(HttpStatusCode.NoContent);
}
// GET: odata/PAYMENTS(5)/DATE_DIM
[EnableQuery]
public SingleResult<DATE_DIM> GetDATE_DIM([FromODataUri] int key)
{
return SingleResult.Create(db.PAYMENTS.Where(m => m.PAYMENT_KEY == key).Select(m => m.DATE_DIM));
}
// GET: odata/PAYMENTS(5)/PROVIDERS
[EnableQuery]
public SingleResult<PROVIDERS> GetPROVIDERS([FromODataUri] int key)
{
return SingleResult.Create(db.PAYMENTS.Where(m => m.PAYMENT_KEY == key).Select(m => m.PROVIDERS));
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
private bool PAYMENTSExists(int key)
{
return db.PAYMENTS.Count(e => e.PAYMENT_KEY == key) > 0;
}
}
}
Lastly, the PAYMENTS.cs model:
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated from a template.
//
// Manual changes to this file may cause unexpected behavior in your application.
// Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace HealthcareWebApp
{
using System;
using System.Collections.Generic;
public partial class PAYMENTS
{
[System.ComponentModel.DataAnnotations.Key] //manually added by ataft
public int PAYMENT_KEY { get; set; }
public string DRG_Definition { get; set; }
public string Provider_Id { get; set; }
public string Hospital_Referral_Region_Description { get; set; }
public Nullable<decimal> Total_Discharges_ { get; set; }
public Nullable<decimal> Covered_Charges { get; set; }
public Nullable<decimal> Total_Payments { get; set; }
public Nullable<decimal> Medicare_Payments { get; set; }
public int Year { get; set; }
public virtual DATE_DIM DATE_DIM { get; set; }
public virtual PROVIDERS PROVIDERS { get; set; }
}
}
It's an issue about filter and groupby is filter can't apply to groupby or aggregated property and resolve in WebAPI/OData 5.9.1.
https://www.nuget.org/packages/Microsoft.AspNet.OData/5.9.1
And in your scenario, apply will always executed first and then filter get executed, so when $apply=groupby((Provider_Id),aggregate(Total_Payments with sum as Total_Payments)), the result won't contain DRG_Definition, so the filter failed, if you want to filter first, you should use filter in apply, like $apply=filter(Name eq 'Lowest')/groupby((Name))
FYI the spec http://docs.oasis-open.org/odata/odata-data-aggregation-ext/v4.0/odata-data-aggregation-ext-v4.0.html
No matter what i do i cannot get injection working with Topshelf, Autofac and self hosted Owin.
I have followed the documentation in http://autofac.readthedocs.org/en/latest/integration/webapi.html#owin-integration and read Autofac WebApi 2 OWIN Not Working, but I am still unable to inject a simple class into my apicontroller.
The 'almost' complete app is posted here.
No matter what i do I cannot get an IEmail instance injected into the EmailController. Can anyone suggest a solution
// topshelf startup code
class Program
{
static void Main(string[] args)
{
HostFactory.Run(c =>
{
//c.UseAutofacContainer(container);
c.RunAsNetworkService();
c.Service<SampleService>(s =>
{
s.ConstructUsing(name => new SampleService());
s.WhenStarted((service, control) => service.Start());
s.WhenStopped((service, control) => service.Stop());
});
});
}
}
// lifted from http://autofac.readthedocs.org/en/latest/integration/webapi.html#owin-integration
public class StartupConfig
{
public void Configure(IAppBuilder appBuilder)
{
var config = new HttpConfiguration();
config.MapHttpAttributeRoutes(); // using attribute based routing because I prefer it
var builder = new Autofac.ContainerBuilder(); // Create the container builder.
builder.RegisterApiControllers(Assembly.GetExecutingAssembly()); // Register the Web API controllers.
builder.RegisterWebApiFilterProvider(config); // optional
builder.RegisterType<Email>().As<IEmail>().InstancePerRequest();
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
appBuilder.UseAutofacMiddleware(container);
appBuilder.UseAutofacWebApi(config); // Make sure the Autofac lifetime scope is passed to Web API.
appBuilder.UseWebApi(config); // enable web-api
string filedir = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "../../web");
appBuilder.UseFileServer(new FileServerOptions
{
EnableDefaultFiles = true,
DefaultFilesOptions =
{
DefaultFileNames = new[] { "Index.html" }
},
EnableDirectoryBrowsing = true,
FileSystem = new PhysicalFileSystem(filedir),
});
}
}
// topshelf hosted service to start
public class SampleService
{
public bool Start()
{
if (WebApplication == null)
{
WebApplication = WebApp.Start
(
new StartOptions
{
Port = 1234
},
appBuilder =>
{
new StartupConfig().Configure(appBuilder);
}
);
}
return true;
}
public bool Stop()
{
return true;
}
protected IDisposable WebApplication
{
get;
set;
}
}
// sample controller
public class EmailController : ApiController
{
public IEmail MyModel; /** always NULL **/
[HttpGet]
[Route("api/emails/{id}")]
public IHttpActionResult get(int id)
{
}
}
Nuget packages
<packages>
<package id="Autofac" version="3.5.0" targetFramework="net452" />
<package id="Autofac.Owin" version="3.1.0" targetFramework="net452" />
<package id="Autofac.WebApi" version="3.1.0" targetFramework="net452" />
<package id="Autofac.WebApi2" version="3.4.0" targetFramework="net452" />
<package id="Autofac.WebApi2.Owin" version="3.3.0" targetFramework="net452" />
<package id="EntityFramework" version="6.0.0" targetFramework="net452" />
<package id="Microsoft.AspNet.WebApi.Client" version="5.2.2" targetFramework="net45" />
<package id="Microsoft.AspNet.WebApi.Core" version="5.2.2" targetFramework="net45" />
<package id="Microsoft.AspNet.WebApi.Owin" version="5.2.2" targetFramework="net45" />
<package id="Microsoft.Owin" version="3.0.1" targetFramework="net452" />
<package id="Microsoft.Owin.FileSystems" version="3.0.1" targetFramework="net452" />
<package id="Microsoft.Owin.Host.HttpListener" version="3.0.1" targetFramework="net452" />
<package id="Microsoft.Owin.Hosting" version="3.0.0" targetFramework="net45" />
<package id="Microsoft.Owin.StaticFiles" version="3.0.1" targetFramework="net452" />
<package id="Newtonsoft.Json" version="6.0.4" targetFramework="net45" />
<package id="Owin" version="1.0" targetFramework="net45" />
<package id="Topshelf" version="3.1.4" targetFramework="net45" />
<package id="Topshelf.Autofac" version="1.0.0" targetFramework="net452" />
</packages>
In order to inject into the apicontroller here
public class EmailController : ApiController
{
public IEmail MyModel; // <---
[HttpGet]
[Route("api/emails/{id}")]
public IHttpActionResult get(int id)
{
}
}
I was missing [PropertiesAutowired] when registering the api controller builder.RegisterApiControllers(Assembly.GetExecutingAssembly()).PropertiesAutowired();
You also dont have a constructor for your Api Controller. Once you have constructor, the service will resolve itself if it is in the Container.
public class EmailController : ApiController
{
public IEmail MyModel;
public EmailController(IEmail MyModel){
this.MyModel = MyModel;
}
[HttpGet]
[Route("api/emails/{id}")]
public IHttpActionResult get(int id)
{
}
}