Asp.net core 2 with angular 6 template - asp.net

I am looking for a template to use asp.net core 2.0 with angular 6 in one solution with f5 hit to run the application.
Can you help find such request ?
Thanks

tutorial
here:
I would not use
Microsoft.DotNet.Web.Spa.ProjectTemplates::2.0.0-rc1-final
but
Microsoft.DotNet.Web.Spa.ProjectTemplates::2.0.0
You can use Angular6.
The magic is that .net core starts new command line itself and runs npm script.
app.UseSpa(spa =>
{
// To learn more about options for serving an Angular SPA from ASP.NET Core,
// see https://go.microsoft.com/fwlink/?linkid=864501
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseAngularCliServer(npmScript: "start");
}
});
npm start is by default alias for ng serve.
I do have working project with Angular6 and Core 2.
My project.csproj
...
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
<TypeScriptToolsVersion>Latest</TypeScriptToolsVersion>
<IsPackable>false</IsPackable>
<SpaRoot>ClientApp\</SpaRoot>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.6" />
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="2.0.0" />
</ItemGroup>
...
and Startup.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.AspNetCore.SpaServices.AngularCli;
namespace AngularSPA
{
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();
// In production, the Angular files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/dist";
});
}
// 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.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseSpaStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller}/{action=Index}/{id?}");
});
app.UseSpa(spa =>
{
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseAngularCliServer(npmScript: "start");
}
});
}
}
}
But I only have aesthetic problem with built-in command line, you can see my question here.

I created one, it is on GitHub, it could be a good starting point but it is not perfect, it should grow and evolve during next months...
https://github.com/JuanGarciaCarmona/AspNetCore21Ang6Template
Also there is an article in Code Project that explains how to use it.
https://www.codeproject.com/Articles/1246748/Angular-within-ASP-NET-Core
I hope it helps.

Related

Launch ASP.NET Core API from windows service

I have a small API created from a ASP.NET core Api template in visual studio 22 that targets .NET6.
For testing\debuging I'm launching the API using console application and everything works.
But for production I need this API to be started from a windows service and I have no idea how to make it.
I could simply put the .exe in same folder as the service and call it, but far as I now if no user logged in the console app won't start.
So the idea is to pack the API together with all services and start it when windows service starts.
I've made a small test by creating a static class name "Test.cs" with a method named "Start" and copy all the code from "Program.cs" and call the "Start" method from a test application.
The API starts and stays listening to the endpoints but for some reason doesn't map the controllers from project controllers folder.
all OK when starting API from default
controllers not mapped when start API from static method
program.cs
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
//to avoid json serialize camel casing
builder.Services.AddControllers().AddJsonOptions(opts =>
{
opts.JsonSerializerOptions.PropertyNamingPolicy = null;
opts.JsonSerializerOptions.NumberHandling = System.Text.Json.Serialization.JsonNumberHandling.AllowNamedFloatingPointLiterals; //para aceitar NAN, infinitos etc no json
});
//////////
//Nedeed
builder.Services.AddCors(options =>
{
options.AddPolicy("CorsPolicy", builder => builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseCors("CorsPolicy");
//app.UseAuthorization();
app.MapControllers();
app.Run();
test.cs
namespace ProjectX.Api
{
public static class Test
{
public static void Start()
{
var builder = WebApplication.CreateBuilder();
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
//to avoid json serialize camel casing
builder.Services.AddControllers().AddJsonOptions(opts =>
{
opts.JsonSerializerOptions.PropertyNamingPolicy = null;
opts.JsonSerializerOptions.NumberHandling = System.Text.Json.Serialization.JsonNumberHandling.AllowNamedFloatingPointLiterals; //para aceitar NAN, infinitos etc no json
});
//////////
//Nedeed
builder.Services.AddCors(options =>
{
options.AddPolicy("CorsPolicy", builder => builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
});
var app = builder.Build();
app.UseSwagger();
app.UseSwaggerUI();
app.UseHttpsRedirection();
app.UseCors("CorsPolicy");
//app.UseAuthorization();
app.MapControllers();
app.Run();
}
}
}
tester app
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace ProjectX.Tester
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
try
{
ProjectX.Api.Test.Start();
}
catch (Exception ex )
{
}
}
}
}
You can run the exe file of Web Api directly in Start():
public static void Start()
{
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.CreateNoWindow = false;
startInfo.UseShellExecute = false;
startInfo.FileName = "Your Path\\ProjectName.exe";
startInfo.WindowStyle = ProcessWindowStyle.Normal;
startInfo.Arguments = "";
try
{
using (Process exeProcess = Process.Start(startInfo))
{
exeProcess.WaitForExit();
}
}
catch
{
//Log error.
}
}
Then you can successfully call the API in the project:
If you want to apply Swagger, please add the following code in the production environment in Program.cs:
app.UseSwagger();
app.UseSwaggerUI();
Result:
Hope this can help you.

Angular + Web API Error Only In Production

About the App
I have an Angular 8 App that uses .Net REST APIs that I inherited from a previous employee (I am new to both frameworks). It has been under development for a few months and has been successfully published to the Production server for testing several times throughout development.
The Issue
After the last publish to the Production server, I am receiving two errors in the console stating Unexpected token < in JSON at position 0 for the API call api/MtUsers/GetLoggedInUser which is called on the backend of the home component. I did not update any code in the home component or the MTUsersController since the last time changes were published to production.
Observations
Error only appears in production
Error still exists if I checkout an older (previously working) commit and publish
Visual Studio started complaining about experimental decorators and missing modules on publish (fixed by restarting VS)
Calling the API using postman appears to return index.html in production but returns the MtUser object in localhost
What I've Tried
Clean solution and re-publish
Checkout last known working commit and publish
Recycle application pool and restart website in IIS
Try various code changes related to website configuration
Relevant Code
I'm not too sure what is most "relevant" to this issue, so I am providing the code specified in the error and the startup.cs file. Let me know if something else would be more useful.
home.component.ts
import { Component } from '#angular/core';
import { MtUser } from 'src/app/core/models/mtUser.model'
import { MtUserService } from 'src/app/core/services/mtUser.service';
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
})
export class HomeComponent {
loadingLoggedInUserInfo = true;
loggedInUser: MtUser = <MtUser>{};
/** home ctor */
constructor(
private mtUserService: MtUserService){
document.getElementsByClassName('main-content')[0].scroll(0, 0);
this.mtUserService.GetLoggedInUser()
.subscribe(response => {
this.loadingLoggedInUserInfo = false;
this.loggedInUser = response;
});
}
}
MtUserService
import { Injectable } from '#angular/core';
import { MtUser } from 'src/app/core/models/mtUser.model';
import { environment } from 'src/environments/environment';
import { HttpClient } from '#angular/common/http';
#Injectable({ providedIn: 'root', })
export class MtUserService {
constructor(private http: HttpClient) { }
GetLoggedInUser() {
return this.http.get<MtUser>(environment.apiUrl + '/MtUsers/GetLoggedInUser');
}
}
MtUsersController
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using MT8.Data;
using MT8.Models;
using MT8.Utilities;
namespace MT8.Controllers
{
[Authorize]
[Route("api/[controller]")]
[ApiController]
public class MtUsersController : Mt8ControllerBase
{
private readonly Mt8Context _context;
public MtUsersController(Mt8Context context)
{
_context = context;
}
// GET: api/MtUsers/GetLoggedInUser
[HttpGet("GetLoggedInUser")]
public async Task<ActionResult<MtUser>> GetLoggedInUser()
{
var loggedInUserName = ApplicationEnvironment.GetLoggedInUserName(this.HttpContext);
var loggedInUser = await this._context.MtUsers
.SingleOrDefaultAsync(u => u.UserName == loggedInUserName);
if (loggedInUser == null)
return NotFound();
return loggedInUser;
}
}
}
Startup.cs
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.SpaServices.AngularCli;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.EntityFrameworkCore;
using MT8.Data;
using Microsoft.AspNetCore.Server.IISIntegration;
using System.Threading.Tasks;
using MT8.Utilities;
namespace MT8
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
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.AddControllersWithViews();
// In production, the Angular files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/dist";
});
services.AddCors(options =>
{
options.AddPolicy(MyAllowSpecificOrigins,
builder =>
{
builder.WithOrigins("http://example.com",
"http://www.contoso.com");
});
});
services.AddDbContext<Mt8Context>(options =>
options.UseSqlServer(Configuration.GetConnectionString("Mt8Context")));
services.AddAuthentication(IISDefaults.AuthenticationScheme);
services.AddControllers()
.AddJsonOptions(options =>
options.JsonSerializerOptions.Converters.Add(new StringToIntJsonConverter()))
.AddJsonOptions(options =>
options.JsonSerializerOptions.Converters.Add(new StringToNullableIntConverter()))
.AddJsonOptions(options =>
options.JsonSerializerOptions.Converters.Add(new StringToDecimalJsonConverter()))
.AddJsonOptions(options =>
options.JsonSerializerOptions.Converters.Add(new StringToDoubleJsonConverter()))
.AddJsonOptions(options =>
options.JsonSerializerOptions.Converters.Add(new StringToDateTimeJsonConverter()))
.AddJsonOptions(options =>
options.JsonSerializerOptions.Converters.Add(new StringToNullableDateTimeConverter()));
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, Mt8Context dbContext)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
// 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.UseHttpsRedirection();
app.UseStaticFiles();
if (!env.IsDevelopment())
{
app.UseSpaStaticFiles();
}
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller}/{action=Index}/{id?}");
});
app.UseSpa(spa =>
{
// To learn more about options for serving an Angular SPA from ASP.NET Core,
// see https://go.microsoft.com/fwlink/?linkid=864501
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseAngularCliServer(npmScript: "start");
}
});
if (!env.IsProduction())
dbContext.InitializeData();
}
}
}
After lots of trial and error, I determined the issue was with a connection string in the appsettings.Production.json file. It was originally set to Integrated Security=True
when the application was first built and something caused this to stop working all of a sudden. I updated the database to use an SQL login and provided the ID and password in the connection string which fixed the issue.

DevExpress routing appears to break with dotnet core 3.1

I have the following DxDatagrid block in my dotnet core webapp index.cshtml page:
#(Html.DevExtreme().DataGrid<UserModel>()
.ID("grid-container")
.ShowBorders(true)
.DataSource(d => d.Mvc().Controller("UserSearch").LoadAction("Get").Key("UserId"))
.Selection(s => s
.Mode(SelectionMode.Multiple)
.SelectAllMode(SelectAllMode.Page)
)
With this code in place and using dotnet core 2.2 the datasource makes a call to:
http://localhost:5000/api/UserSearch/Get?skip=0&take=10&requireTotalCount=true&_=1600859370033
Having updated to dotnet core 3.1 and updated the DevExpress references in the csproj and _Layout.cshtml files, the routing now attempts to call:
http://localhost:5000/?skip=0&take=10&requireTotalCount=true&_=1600859693687
The startup.cs is this:
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using AccessUsers.Middleware;
using AccessUsers.Models;
using Microsoft.AspNetCore.HttpOverrides;
namespace WebAppTest
{
public class Startup
{
private readonly IConfiguration _config;
private readonly AppSettings _appSettings;
public Startup(IConfiguration config)
{
_config = config;
_appSettings = _config.Get<AppSettings>();
}
// This method gets called by the runtime. Use this method to add services to the container.
public void 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 => false;
// options.MinimumSameSitePolicy = SameSiteMode.None;
options.MinimumSameSitePolicy = SameSiteMode.Unspecified;
options.OnAppendCookie = cookieContext => cookieContext.CookieOptions.SameSite = SameSiteMode.Unspecified;
options.OnDeleteCookie = cookieContext => cookieContext.CookieOptions.SameSite = SameSiteMode.Unspecified;
});
services.Configure<AppSettings>(_config);
services.AddSingleton<APIService>();
services.AddSingleton<UserService>();
services.AddSingleton<ShipToService>();
services.AddApplicationInsightsTelemetry();
services.AddLocalization(options => options.ResourcesPath = "Resources");
services.AddSession();
services.AddMemoryCache();
services.AddRazorPages().AddNewtonsoftJson(options => {
options.SerializerSettings.ContractResolver = new Newtonsoft.Json.Serialization.DefaultContractResolver();
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
}).AddXmlSerializerFormatters();
services.UseOpenIDConnectMiddleware(new OpenIDConnectMiddlewareOptions
{
BaseUrl = _appSettings.API.BaseUrl,
AppName = _appSettings.AppName,
ClientId = _appSettings.API.ClientId,
ClientSecret = _appSettings.API.ClientSecret,
Secure = !_appSettings.Local
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedProto
});
if (_appSettings.Local)
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
app.UseGlobalLoginMiddleware();
app.UseHttpsRedirection();
}
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();
app.UseEndpoints(endpoints => {
endpoints.MapRazorPages();
});
CultureInfo[] allCultures = CultureInfo.GetCultures(CultureTypes.AllCultures);
string location = Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location);
var supportedCultures = allCultures.Where(c => Directory.Exists(Path.Combine(location, c.Name)) && c.LCID != 127).ToList();
app.UseRequestLocalization(new RequestLocalizationOptions
{
DefaultRequestCulture = new RequestCulture("en-US"),
SupportedCultures = supportedCultures,
SupportedUICultures = supportedCultures
});
}
}
}
The csproj contains this:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<AspNetCoreHostingModel>OutOfProcess</AspNetCoreHostingModel>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="3.1.6" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.7" />
<PackageReference Include="Microsoft.IdentityModel.Protocols.OpenIdConnect" Version="6.7.1" />
<PackageReference Include="DevExtreme.AspNet.Data" Version="2.7.1" />
<PackageReference Include="DevExtreme.AspNet.Core" Version="20.1.7" />
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="6.7.1" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.7.1" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.14.0" />
<PackageReference Include="Amazon.Lambda.AspNetCoreServer" Version="5.0.0" />
</ItemGroup>
</Project>
The controller.cs contains this:
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using AccessUsers.Models;
using DevExtreme.AspNet.Data;
using DevExtreme.AspNet.Mvc;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
namespace WebAppTest.Pages
{
[Route("api/[controller]/[action]")]
public class UserSearchController : Controller
{
private readonly UserService _userService;
public UserSearchController(UserService userService)
{
_userService = userService;
}
[HttpGet]
public object Get(DataSourceLoadOptions loadOptions)
{
var result = DataSourceLoader.Load(GetProfiles(user:new UserModel(),useDummyData: true), loadOptions);
return result;
}
The _Layout.cshtml contains this:
<script src="https://cdn3.devexpress.com/jslib/20.1.7/js/dx.all.js" integrity="sha384-LAn+t9UxSqkm8biNuoUbJcohKoYmbiFRfVLERIJ4I3RyEpAIBizEcIztuXPG9Cqg sha512-OAjfsw+eXv345AD9H6kDJLChXetpJD6ChGgDvjVIEumiHYulOLXIO/Do5gxljW2GUgpObic42JyS8a0wZqb1Fw==" crossorigin="anonymous"></script>
<script src="https://cdn3.devexpress.com/jslib/20.1.7/js/dx.aspnet.mvc.js" integrity="sha384-5rtF4jUX5Hez5YwkW7PHC/0XplJQS26qVUCfec8fBX0IkoR1y35EXHkZDbgeMh3x sha512-0eJebJTnN45FCtUOrVqxk5p73OMWsx94vLQpnlRtDp/CKbssiUR0j0os+0y01fvzDtdtnEKSeau32g30fgtrYQ==" crossorigin="anonymous"></script>
As specified here:
https://js.devexpress.com/Documentation/Guide/Common/Distribution_Channels/CDN/
I'm sure it's the change to dotnet core 3.1 which caused the routing to break because the functionality of the application hasn't changed, but I can't see what specifically breaks it.
Startup.ConfigureServices doesn't add support for controllers, only for Razor Pages with :
services.AddRazorPages().AddNewtonsoftJson(options => {
...
}).AddXmlSerializerFormatters();
From the Remarks in the method's documentation
This method configures the MVC services for the commonly used features for pages.
To add services for controllers for APIs call AddControllers(IServiceCollection).
The controller is never registered right now, so the code that tries to generate the action URL
.DataSource(d => d.Mvc().Controller("UserSearch").LoadAction("Get")
fails to find anything and returns an empty string.
To fix this, add controller support :
services.AddControllers().AddNewtonsoftJson(options => {
...
}).AddXmlSerializerFormatters();
services.AddRazorPages();
Controllers should be added in the endpoint routing code in Configure as well, with MapControllers :
app.UseEndpoints(endpoints => {
endpoints.MapRazorPages();
endpoints.MapControllers();
});

ASP.NET Identity - how to extend the login expiration time [duplicate]

This question already has answers here:
Cookie Authentication expiring too soon in ASP.NET Core
(3 answers)
Session timeout in ASP.NET
(15 answers)
Closed 5 years ago.
My ASP.NET Core 1.1.1 app is logging out after about 30 minutes. I'm using some session variables and have installed Microsoft.AspNetCore.Session package and have configured the app as shown below. Have set the session expiration time to 2 hours. From what I've read the Authentication Cookie time by default is 14 days so that should not be an issue. Question: It seems I may be missing something here. What needs to be done to make the app not logout before 2 hours? What are the possible causes and what is a possible solution?
Note: The app is running on IIS 10 on windows 10. The Application Pool for the app is set to Not Managed Code and it's default idle time out is 20 minutes with idle timtout-action set to Terminate. But from what I've heard the IIS Application Pool Idle Time-out Settings play no role in ASP.NET Core.
Startup.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using MyProjName.Data;
using MyProjName.Models;
using MyProjName.Services;
namespace MyProjName
{
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
if (env.IsDevelopment())
{
// For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709
builder.AddUserSecrets<Startup>();
}
builder.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
var connection = #"Server=MyWin10Machine;Database=MySQL20012Db;User Id=TestUSer;Password=TestPassword";
services.AddDbContext<MyProjNameContext>(options => options.UseSqlServer(connection));
// Add framework services.
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<ApplicationUser, ApplicationRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddMvc();
services.AddDistributedMemoryCache();
services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromHours(2);
options.CookieHttpOnly = true;
}); //extended the session timout to 2 hours. Default is 20 minutes
// Add application services.
services.AddTransient<IEmailSender, AuthMessageSender>();
services.AddTransient<ISmsSender, AuthMessageSender>();
}
// 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();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseIdentity();
app.UseSession(); //must come before app.UseMvc()
// Add external authentication middleware below. To configure them please see http://go.microsoft.com/fwlink/?LinkID=532715
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}

Nancy 500 server error with dotnetcore and kestrel

I am trying to use NancyFX (clint-eastwood) with dotnetcore1.1 and dotnet-cli 1.0.0-rc4-004771. My current project structure is -
CustomBootstrapper.cs
HomeModule.cs
index.sshtml
nancyapp.csproj
Program.cs
Startup.cs
And codes are -
nancyapp.csproj
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp1.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Owin">
<Version>1.1.0</Version>
</PackageReference>
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel">
<Version>1.1.0</Version>
</PackageReference>
<PackageReference Include="Nancy">
<Version>2.0.0-clinteastwood</Version>
</PackageReference>
</ItemGroup>
</Project>
Program.cs
using System.IO;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
namespace nancyapp
{
class Program
{
static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.Build();
host.Run();
}
}
}
Startup.cs
using Microsoft.AspNetCore.Builder;
using Nancy.Owin;
namespace nancyapp
{
public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.UseOwin(x => x.UseNancy());
}
}
}
HomeModule.cs
using Nancy;
namespace nancyapp
{
public class HomeModule : NancyModule
{
public HomeModule()
{
Get("/", _ => { return View["index.sshtml"]; });
Get("/test/{name}", args => new Person() { Name = args.name });
}
}
public class Person
{
public string Name { get; set; }
}
}
index.sshtml
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
Welcome to Nancy App.
</body>
</html>
CustomBootstrapper.cs is currently empty.
When I try to access Get("/test/{name}", args => new Person() { Name = args.name }); from a rest client i get the expected result.
However, when I try to access to root or Get("/", _ => { return View["index.sshtml"]; });, I get a 500 server error saying -
Error details are currently disabled. To enable it, please set
TraceConfiguration.DisplayErrorTraces to true. For example by
overriding your Bootstrapper's Configure method and calling
environment.Tracing(enabled: false, displayErrorTraces: true)
I tried following the instruction in the error message and enable error tracing by including the following code in CustomBootstrapper.cs
protected override void ApplicationStartup(Nancy.TinyIoc.TinyIoCContainer container, IPipelines pipelines)
{
var environment = GetEnvironment();
environment.Tracing(true, true);
}
But then I get the following error when trying to run the application with dotnet run
Unhandled Exception: System.ArgumentException: An item with the same
key has already been added. Key: Nancy.TraceConfiguration at
System.ThrowHelper.ThrowAddingDuplicateWithKeyArgumentException(Object key) at
System.Collections.Generic.Dictionary`2.Insert(TKey key,TValue value, Boolean add) at
nancyapp.CustomBootstrapper.ApplicationStartup(TinyIoCContainer container, IPipelines pipelines) in D:\TempWork\nancyapp\CustomBootstrapper.cs:line 17 at
Nancy.Bootstrapper.NancyBootstrapperBase`1.Initialise() at
Nancy.Owin.NancyMiddleware.UseNancy(NancyOptions options) at
Nancy.Owin.DelegateExtensions.UseNancy(Action`1 builder, NancyOptionsoptions) at
nancyapp.Startup.<>c.<Configure>b__0_0(Action`1 x) in D:\TempWork\nancyapp\Startup.cs:line 10 at
Microsoft.AspNetCore.Builder.OwinExtensions.UseOwin(IApplicationBuilder builder, Action`1 pipeline) at
nancyapp.Startup.Configure(IApplicationBuilder app) in D:\TempWork\nancyapp\Startup.cs:line 10
--- End of stack trace from previous location where exception was thrown --- at
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at
Microsoft.AspNetCore.Hosting.ConventionBasedStartup.Configure(IApplicationBuilder app) at
Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication() at
Microsoft.AspNetCore.Hosting.WebHostBuilder.Build() at
nancyapp.Program.Main(String[] args) in D:\TempWork\nancyapp\Program.cs:line 11
I am not sure what's causing the error or how to enable tracing. Can anyone help?
The are two problems here :
The 500 is because the view was not found , what you need to do is provide a root path by implementing IRootPathProvider and return Directory.GetCurrent().
Secondly to enable tracing you need public override void Configure(INancyEnvironment environment) this adds the keys hence you the exception you are getting.
You may get the same server error (500) when using Nancy in a .NET Core 3.1 app in combination with Owin >= v3.
I've solved the issue by downgrading Microsoft.AspNetCore.Owin from v3.x to v2.2.0.
My running setup was the following after the downgrade:
It's also fine to return a simple text for testing:
Get("/", _ => { return new TextResponse(HttpStatusCode.OK, "Hello world!"); });

Resources