How to use Entity Framework 7 in class library? - asp.net

I want to make the work with data in a class library with asp.net core 1. I created MyDbContext in a class library:
public class MyDbContext: DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<UserProfile> Profiles { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// maybe need to add foreign key
modelBuilder.Entity<User>()
.HasOne(p => p.Profile)
.WithOne(u => u.User)
.HasForeignKey<UserProfile>(p => p.UserId);
}
}
My project.json in class library:
{
"version": "1.0.0-*",
"description": "DatabaseCore Class Library",
"authors": [ "alex-pc" ],
"tags": [ "" ],
"projectUrl": "",
"licenseUrl": "",
"frameworks": {
"net451": {
"dependencies": {
"EntityFramework.MicrosoftSqlServer": "7.0.0-rc1-final",
"EntityFramework.Commands": "7.0.0-rc1-final"
},
"frameworkAssemblies": {
"System.Runtime": "4.0.10.0",
"System.Data.Entity": "4.0.0.0",
"System.Data": "4.0.0.0",
"System.ComponentModel.DataAnnotations": "4.0.0.0"
}
}
},
"dependencies": {
}
}
And updated startup.cs in web application:
public class Startup
{
public Startup(IHostingEnvironment env)
{
// Set up configuration sources.
var builder = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddEnvironmentVariables();
if (env.IsDevelopment())
{
builder.AddApplicationInsightsSettings(developerMode: true);
}
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; set; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<MyDbContext>(options =>
{
options.UseSqlServer(Configuration["Data:ConnectionString"]);
});
// Add framework services.
services.AddApplicationInsightsTelemetry(Configuration);
//services.AddAuthorization(options =>
//{
// options.AddPolicy("API", policy =>
// {
// policy.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme);
// policy.RequireAuthenticatedUser();
// });
//});
services.AddAuthentication();
services.AddCaching();
services.AddMvc();
}
// 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)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseApplicationInsightsRequestTelemetry();
if (env.IsDevelopment())
{
app.UseBrowserLink();
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseIISPlatformHandler();
app.UseApplicationInsightsExceptionTelemetry();
app.UseStaticFiles();
app.UseJwtBearerAuthentication(options =>
{
options.AutomaticAuthenticate = true;
options.Audience = "resource_server_1";
options.Authority = "http://localhost:4871/";
options.RequireHttpsMetadata = false;
options.TokenValidationParameters.ValidateLifetime = true;
});
// Add a new middleware issuing tokens.
app.UseOpenIdConnectServer(options =>
{
options.AllowInsecureHttp = true;
options.AuthorizationEndpointPath = PathString.Empty;
options.TokenEndpointPath = "/connect/token";
options.Provider = new AuthorizationProvider();
});
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
// Entry point for the application.
public static void Main(string[] args) => WebApplication.Run<Startup>(args);
}
My appsettings.json:
{
"ApplicationInsights": {
"InstrumentationKey": ""
},
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Verbose",
"System": "Information",
"Microsoft": "Information"
}
},
"Data": {
"ConnectionString": "Data Source=DESKTOP-R3AP4AT\\SQLEXPRESS;Initial Catalog=mydb;Integrated Security=True;Connect Timeout=15;Encrypt=False;TrustServerCertificate=True;ApplicationIntent=ReadWrite;MultiSubnetFailover=False"
}
}
Now I want to make the migration to create the database. Using commands in cmd
dnvm use 1.0.0-rc1-final
dnx ef migrations add MyFirstMigration
dnx ef database update
First, all performed well, the database was created, but does not create a table, database is empty. If i added this code:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(
#"Data Source=DESKTOP-R3AP4AT\\SQLEXPRESS;Initial Catalog=mydb;Integrated Security=True;Connect Timeout=15;Encrypt=False;TrustServerCertificate=True;ApplicationIntent=ReadWrite;MultiSubnetFailover=False");
base.OnConfiguring(optionsBuilder);
}
error - instance crashes,
Result:

I think you missed
"commands": {
"ef": "EntityFramework.Commands"
},
in the project.json of your library.
When I moved my EF model into a library I followed the instructions from here: http://www.jerriepelser.com/blog/moving-entity-framework-7-models-to-external-project
Meanwhile I moved from RC1 to RC2 nightly and my project.json of the library looks like this.
{
"version": "1.0.0-*",
"description": "DhrData Class Library",
"authors": [ "noox" ],
"tags": [ "" ],
"projectUrl": "",
"licenseUrl": "",
"dependencies": {
"Microsoft.EntityFrameworkCore.Commands": "1.0.0-rc2-20270",
"Microsoft.EntityFrameworkCore.SqlServer": "1.0.0-rc2-20270"
},
"commands": {
"ef": "EntityFramework.Commands"
},
"frameworks": {
"dnx451": {
"frameworkAssemblies": {
"System.Reflection": ""
}
},
"dnxcore50": {
"dependencies": { }
}
}
}
Lately I did not use migration because I had too much changes while playing around with EF Core. Instead I created a console application which recreates the database and fills it with some data. This is already for RC2 (and you probably do not need the custom Appsettings).
using System;
using DhrData.Models;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.PlatformAbstractions;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore;
namespace DhrConsoleApp
{
public class Program
{
private IServiceProvider serviceProvider;
public IConfiguration Configuration { get; set; }
public AppSettings AppSettings { get; set; } // object for custom configuration
private void ConfigureServices(IServiceCollection serviceCollection)
{
// Add framework services.
serviceCollection
//.AddEntityFramework() // RC1
.AddEntityFrameworkSqlServer() // RC2
.AddDbContext<DhrDbContext>(options => options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));
serviceCollection
.AddScoped(p => new DhrDbContext(p.GetService<DbContextOptions<DhrDbContext>>()));
serviceCollection.Configure<AppSettings>(s => Configuration.GetSection("AppSettings"));
}
public static void Main(string[] args)
{
var applicationEnvironment = PlatformServices.Default.Application;
new Program(applicationEnvironment);
}
public Program(IApplicationEnvironment env)
{
//var loggerFactory = new LoggerFactory();
//loggerFactory.AddConsole(LogLevel.Debug);
// Set up configuration sources.
var configurationBuilder = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddJsonFile("config.{env.EnvironmentName.ToLower()}.json", optional: true)
.AddEnvironmentVariables();
Configuration = configurationBuilder.Build();
// custom application settings
AppSettings = new AppSettings();
Configuration.GetSection("AppSettings").Bind(AppSettings);
var serviceCollection = new ServiceCollection();
ConfigureServices(serviceCollection);
serviceProvider = serviceCollection.BuildServiceProvider();
using (var dbContext = serviceProvider.GetService<DhrDbContext>())
{
RecreateDb(dbContext);
}
}
private void RecreateDb(DhrDbContext dbContext)
{
Console.WriteLine("EnsureDeleted ...");
dbContext.Database.EnsureDeleted();
Console.WriteLine("EnsureDeleted ... Done!");
Console.WriteLine("EnsureCreated ...");
dbContext.Database.EnsureCreated();
Console.WriteLine("EnsureCreated ... Done!");
Console.WriteLine("");
}
}
}
If not necessary I would not recommend to update to RC2 as long as it is not final. It's a pain. But there are quite some bugs in EF RC1 which have already been fixed in RC2 nightly builds.

The recommended approach is to leave the connection string in the AddDbContext<TContext>() call in the application's Startup.cs and to use MigrationsAssembly() to tell EF where the migrations will be located (which should probably be alongside the DbContext). E.g.:
services.AddEntityFramework().AddDbContext<MyDbContext>(options => options
.UseSqlServer(connectionString)
.MigrationsAssembly(assemblyName));

Related

How to set the minimum loglevel with serilog's application insights sink

I'm using Serilog to log to application insights, but I am only getting the log levels warning, error, and critical to be logged. In appsettings.json, I have the minimum loglevel set to verbose, and this logs everything with the file and console sinks.
By default, application insights can only logs Warning and above. In code (in configure logging), I can add a filter to override this default of warning and above. I preferer to do this in appsettings, with the other logging configuration.
How so I use appsettings to allow Serilog to log all levels to Application Insights?
I am getting some logs in application insights so the connectivity is
working.
I see all loglevels in the logfile and on the console.
Where configuting logging,if I add LogLevel filer (commented out) I can make it work. I needs to work from appsettings.
host.ConfigureLogging(
loggingBuilder =>
{
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
var logger = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.CreateLogger();
loggingBuilder.AddApplicationInsights();
loggingBuilder.AddSerilog(logger, dispose: true);
//loggingBuilder.AddFilter<ApplicationInsightsLoggerProvider>("", LogLevel.Trace);
}
);
This is my code and the results:
Here is my appsettings:
"Serilog": {
"AllowedHosts": "*",
"Enrich": [ "WithMachineName" ],
"MinimumLevel": {
"Default": "Verbose",
"Override": {
"Microsoft": "Warning",
"System": "Warning"
}
},
"WriteTo": [
{
"Name": "Console"
},
{
"Name": "File",
"Args": {
"fileSizeLimitBytes": "1048576",
"formatter": "Serilog.Formatting.Compact.CompactJsonFormatter, Serilog.Formatting.Compact , Version=1.0.0.0, Culture=neutral, PublicKeyToken=24c2f752a8e58a10",
"path": "c:\\LogFiles\\Publisher\\Test1\\_log.txt",
"retainedFileCountLimit": null,
"rollingInterval": "Day",
"rollOnFileSizeLimit": "true"
}
},
{
"Name": "ApplicationInsights",
"Args": {
"restrictedToMinimumLevel": "Verbose",
"telemetryConverter": "Serilog.Sinks.ApplicationInsights.Sinks.ApplicationInsights.TelemetryConverters.TraceTelemetryConverter, Serilog.Sinks.ApplicationInsights"
}
}
]
},
Here's my testing result:
I created my asp.net core mvc application and here's my appsettings.json:
{
"AllowedHosts": "*",
"Serilog": {
"Using": [],
"MinimumLevel": "Verbose",
"WriteTo": [
{
"Name": "Console",
"Args": {
"restrictedToMinimumLevel": "Verbose",
"outputTemplate": "{Timestamp:HH:mm:ss.fff zzz} [{Level}] {Message} {NewLine}{Exception}"
}
},
{
"Name": "ApplicationInsights",
"Args": {
"instrumentationKey": "instrument_key_here",
"restrictedToMinimumLevel": "Verbose",
"telemetryConverter": "Serilog.Sinks.ApplicationInsights.Sinks.ApplicationInsights.TelemetryConverters.TraceTelemetryConverter, Serilog.Sinks.ApplicationInsights"
}
}
],
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId"],
"Properties": {
"Application": "Sample"
}
}
}
My program.cs, add read configuration code and add UseSerilog():
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Serilog;
namespace serilog_appsetting_file_appinsights
{
public class Program
{
public static void Main(string[] args)
{
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.CreateLogger();
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
}).UseSerilog();
}
}
My packages:
<ItemGroup>
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.17.0" />
<PackageReference Include="Serilog.AspNetCore" Version="4.1.0" />
<PackageReference Include="Serilog.Settings.Configuration" Version="3.1.0" />
<PackageReference Include="Serilog.Sinks.ApplicationInsights" Version="3.1.0" />
</ItemGroup>
My controller file:
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Serilog;
using serilog_appsetting_file_appinsights.Models;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
namespace serilog_appsetting_file_appinsights.Controllers
{
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
public IActionResult Index()
{
Log.Verbose("serilog_verbose_info");
Log.Debug("serilog_debug_info");
Log.Information("serilog_information_info");
Log.Warning("serilog_warning_info");
Log.Error("serilog_error_info");
return View();
}
public IActionResult Privacy()
{
return View();
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
}
When debuging in localhost, we can see app insights capturing logs like this, and see console log

Spatial Point data type is not serialized correctly when using custom System.Text.Json serializer for Cosmos .NET v3 SDK

I want to use the System.Text.Json Json serializer with the Cosmos .NET v3 SDK.
So I use:
var client = new CosmosClientBuilder
(accountEndpoint: "https://localhost:8081", "<key>")
.WithCustomSerializer(new SystemTextJsonCosmosSerializer(new JsonSerializerOptions {}))
.Build();
With the custom serializer being (taken from Github issue):
public class SystemTextJsonCosmosSerializer : CosmosSerializer
{
private readonly JsonSerializerOptions _options;
public SystemTextJsonCosmosSerializer(JsonSerializerOptions options)
{
_options = options;
}
/// <inheritdoc />
public override T FromStream<T>(Stream stream)
{
// Have to dispose of the stream, otherwise the Cosmos SDK throws.
// https://github.com/Azure/azure-cosmos-dotnet-v3/blob/0843cae3c252dd49aa8e392623d7eaaed7eb712b/Microsoft.Azure.Cosmos/src/Serializer/CosmosJsonSerializerWrapper.cs#L22
// https://github.com/Azure/azure-cosmos-dotnet-v3/blob/0843cae3c252dd49aa8e392623d7eaaed7eb712b/Microsoft.Azure.Cosmos/src/Serializer/CosmosJsonDotNetSerializer.cs#L73
using (stream)
{
// TODO Would be more efficient if CosmosSerializer supported async
using var memory = new MemoryStream((int)stream.Length);
stream.CopyTo(memory);
byte[] utf8Json = memory.ToArray();
return JsonSerializer.Deserialize<T>(utf8Json, _options);
}
}
/// <inheritdoc />
public override Stream ToStream<T>(T input)
{
byte[] utf8Json = JsonSerializer.SerializeToUtf8Bytes(input, _options);
return new MemoryStream(utf8Json);
}
}
However, the Point data type is then not properly serilized.
public Point Location { get; set; }
It should be (as with Cosmos .NET SDK v3/Newtonsoft , v4 Preview/System.Text.Json) be:
"location": {
"type": "Point",
"coordinates": [
8.0000,
47.0000
]
},
But instead it ends up being:
"location": {
"Position": {
"Coordinates": [
8.0000,
47.0000
],
"Longitude": 8.0000,
"Latitude": 47.0000,
"Altitude": null
},
"Crs": {
"Type": 0
},
"Type": 0,
"BoundingBox": null,
"AdditionalProperties": {}
},
Anyone has idea on why, and how I can make it serialize properly?

HttpContext.Request.Body is disposed when accessing via ApplicationInsights ITelemetryInitializer

I'm trying to log POST, PUT, PATCH json bodies to app insights using ITelemetryInitializer. Every time a post comes in though it seems that my body stream is already disposed of some how. I'm assuming there is something in the request pipeline that I'm not registering/doing properly.
public class RequestBodyLogger : ITelemetryInitializer
{
readonly IHttpContextAccessor httpContextAccessor;
public RequestBodyLogger(IHttpContextAccessor httpContextAccessor)
{
this.httpContextAccessor = httpContextAccessor;
}
public void Initialize(ITelemetry telemetry)
{
try
{
if (telemetry is RequestTelemetry requestTelemetry)
{
if ((httpContextAccessor.HttpContext.Request.Method == HttpMethods.Post ||
httpContextAccessor.HttpContext.Request.Method == HttpMethods.Put ||
httpContextAccessor.HttpContext.Request.Method == HttpMethods.Patch) &&
httpContextAccessor.HttpContext.Request.Body.CanRead)
{
const string jsonBody = "JsonBody";
if (requestTelemetry.Properties.ContainsKey(jsonBody))
{
return;
}
//Allows re-usage of the stream
httpContextAccessor.HttpContext.Request.EnableRewind();
var stream = new StreamReader(httpContextAccessor.HttpContext.Request.Body);
var body = stream.ReadToEnd(); <<Blows here object disposed (stream)
//Reset the stream so data is not lost
httpContextAccessor.HttpContext.Request.Body.Position = 0;
requestTelemetry.Properties.Add(jsonBody, body);
}
}
}
catch (Exception e)
{
}
}
}
Configure services method...
public void ConfigureServices(IServiceCollection services)
{
if (_env.IsDevelopment())
{
services.AddSwaggerGen(c =>
{
c.SwaggerDoc(Constants.ApiVersion, new Info { Title = Constants.ApiName, Version = Constants.ApiVersion });
c.AddSecurityDefinition("Bearer", new ApiKeyScheme { In = "header", Description = "Please enter Bearer Token", Name = "Authorization", Type = "apiKey" });
c.AddSecurityRequirement(new Dictionary<string, IEnumerable<string>> { { "Bearer", Enumerable.Empty<string>() } });
c.IncludeXmlComments($"{AppDomain.CurrentDomain.BaseDirectory}\\TradeJournal.Api.xml");
});
}
services.AddAuthentication(options =>
{
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.Authority = Configuration["IdentityAuthority"];
options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
{
IssuerSigningKeyResolver = (s, securityToken, identifier, parameters) =>
{
var json = new WebClient().DownloadString(parameters.ValidIssuer + "/.well-known/jwks.json");
var keys = JsonConvert.DeserializeObject<JsonWebKeySet>(json).Keys;
return (IEnumerable<SecurityKey>)keys;
},
ValidIssuer = Configuration["IdentityAuthority"],
ValidateIssuerSigningKey = true,
ValidateIssuer = true,
ValidateLifetime = true,
ValidateAudience = false
};
});
services
.AddCors(c =>
{
c.AddPolicy("AllowOrigin", options => options.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod().AllowCredentials());
});
services.AddMvc(opts =>
{
opts.Filters.Add(typeof(ModelStateValidationFilter));
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
.AddJsonOptions(opt =>
{
opt.SerializerSettings.DateFormatString = "yyyy-MM-ddTHH:mm:ssZ";
});
services.AddSingleton<ITelemetryInitializer, RequestBodyLogger>();
services.AddTransient<ExceptionToHttpResponseMiddleware>();
services.AddTransient<MaintenanceMiddleware>();
services.AddRouting(opts =>
{
opts.LowercaseUrls = true;
opts.LowercaseQueryStrings = true;
});
BootstrapLayers(services);
}
```
Configure method...
public void Configure(IApplicationBuilder app)
{
if (_env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
// Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.),
// specifying the Swagger JSON endpoint.
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint($"/swagger/{Constants.ApiVersion}/swagger.json", Constants.ApiName);
});
}
else
{
//The default HSTS value is 30 days.You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseAuthentication();
app.UseCors(options => options.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader().AllowCredentials());
app.UseMiddleware<ExceptionToHttpResponseMiddleware>();
app.UseMiddleware<MaintenanceMiddleware>();
app.UseHttpsRedirection();
app.UseMvc();
}
**Why is the context disposed by the time AI calls this telemetry initializer?**
This is also discussed in github: https://github.com/microsoft/ApplicationInsights-aspnetcore/issues/940#issuecomment-513297006
Since by the time TelemetryInitializers are run, the request body is disposed, your best bet is to read and populate the body into RequestTelemetry when the body is still available. If its a controller or middleware - then retrieve RequestTelemetry there, add body to it. The following is sample code to be written in controller/middleware where you can retrieve request body.
RequestTelemetry reqTelemetry = httpContext?.Features.Get<RequestTelemetry>();
reqTelemetry.Properties.Add("body","body contents").

Stuck figuring out the initialization sequence of ASP.NET Core 2.1

This is a problem that has been hard for me to figure out. I wanted to make a micro-service out of an ASP.NET Core Application. I've been able to deploy .NET Core with Kestrel as an edge server and behind a proxy like Nginx. This seems semi-inconsequential, so haven't spent forever on it, but I can't figure out how to land on a different url other than root when my application starts up. In other words, I've changed the default routing, this is an mvc application, and I added a prefix like this into Startup.cs:
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "SqlServer/{controller=Home}/{action=Index}/{id?}");
});
In production, not a problem, doesn't matter what the default route is, but when I develop in VisualStudio and hit play, I get the blank browser because its pointing to "/" instead of "/SqlServer". Any idea how to fix this?
Also relevant is Program.cs:
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
return WebHost.CreateDefaultBuilder(args)
.UseKestrel(options =>
{
options.Limits.MaxConcurrentConnections = 100;
options.Limits.MaxConcurrentUpgradedConnections = 100;
options.Limits.MaxRequestBodySize = 10 * 1024;
options.Limits.MinRequestBodyDataRate = new MinDataRate(bytesPerSecond: 100, gracePeriod: TimeSpan.FromSeconds(10));
options.Limits.MinResponseDataRate = new MinDataRate(bytesPerSecond: 100, gracePeriod: TimeSpan.FromSeconds(10));
options.Listen(IPAddress.Any, 5000);
options.Listen(IPAddress.Any, 5001, listenOptions =>
{
listenOptions.UseHttps("/Users/ryandines/DevelopmentCode/ExampleProject/testCert.pfx", "notMyPassword");
});
}).UseStartup<Startup>();
}
}
There's 2 ways of changing this setting.
Using Visual Studio
Right click on the project, select "Properties"
Select "Debug" tab
Next to the "Launch browser" checkbox, enter a URL that you want to start when the app runs.
Edit settings manually
Manually add a launchUrl property to the profile, for example:
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:1234/",
"sslPort": 0
}
},
"profiles": {
"<name of profile>": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "http://localhost:1234/cheese",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Local"
}
},
//etc...

Route table in MVC6 for web API not working

I have the following code in Startup.cs:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
}
public void Configure(IApplicationBuilder app)
{
app.UseMvc(routes =>
{
routes.MapRoute(
name: "DefaultApi",
template: "api/{controller=Customers}/{id?}");
});
}
}
… and declared the MVC dependency in project.json:
{
"webroot": "wwwroot",
"version": "1.0.0-*",
"dependencies": {
"Microsoft.AspNet.Server.IIS": "1.0.0-beta3",
"Microsoft.AspNet.Mvc": "6.0.0-beta3"
},
"frameworks": {
"aspnet50": { },
"aspnetcore50": { }
},
"bundleExclude": [
"node_modules",
"bower_components",
"**.kproj",
"**.user",
"**.vspscc"
],
"exclude": [
"wwwroot",
"node_modules",
"bower_components"
]
}
I have the following controller:
using Microsoft.AspNet.Mvc;
using System.Collections.Generic;
namespace WebApplication1.Controllers
{
public class CustomersController : Controller
{
private List<Customer> _Customers = new List<Controllers.Customer>();
public CustomersController()
{
_Customers.Add(new Customer() { ID = 1, Name = "Fred" });
_Customers.Add(new Customer() { ID = 2, Name = "Bob" });
_Customers.Add(new Customer() { ID = 3, Name = "Tim" });
}
public List<Customer> Get()
{
return _Customers;
}
public Customer Get(int ID)
{
Customer Customer = _Customers.Find(c => c.ID == ID);
return Customer;
}
}
public class Customer
{
public int ID { get; set; }
public string Name { get; set; }
}
}
… but when I browse to /api/customers or /api/customers/1 I get a 404 Not Found
Am is missing something? Is the route table for web API in MVC6 supported yet?
If you are trying to port your Asp.Net Web API to MVC 6, you need to have Web API Compatibility Shim . The default startup class code explains it
// Uncomment the following line to add Web API servcies which makes it easier to port Web API 2 controllers.
// You need to add Microsoft.AspNet.Mvc.WebApiCompatShim package to project.json
// services.AddWebApiConventions();
By default it is switched off. Once enabled, you can configure web api route as
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller}/{action}/{id?}",
defaults: new { controller = "Home", action = "Index" });
// Uncomment the following line to add a route for porting Web API 2 controllers.
// routes.MapWebApiRoute("DefaultApi", "api/{controller}/{id?}");
});
More details here
I am bit late to answer this, but you need to put routing attribute
[Route("api/[controller]")]
and remove the api from
template: "api/{controller=Customers}/{id?}");

Resources