Using Tempdata is crashing my application - c#

I'm very new to ASP.NET and am attempting to pass an object between two controllers in a web application I'm making in Visual Studio 2015. The web application is using an ASP.Net 5 Preview Template Web application (if it helps, I think I'm using beta code 7 and I'm not building for DNX Core 5).
The problem I'm having is whenever I try to put anything into the TempData variable, the program seems to crash. For example, in a "Create" method I have:
[HttpPost]
public ActionResult Create(Query query)
{
switch (query.QueryTypeID)
{
case 1:
TempData["Test"] = "Test";
return RedirectToAction("Index", "EventResults");
case 2:
break;
default:
break;
}
return View();
}
In that method, I attempt to add a simple test string under the key "test". When I run the application with that TempData statement in there, I receive an error message stating
An unhandled exception occurred while processing the request.
InvalidOperationException: Session has not been configured for this application >or request.
Microsoft.AspNet.Http.Internal.DefaultHttpContext.get_Session()
I have tried going to the Web.config located in the wwwroot element of the project and adding a "sessionState" object into a "system.web" element, but this had no effect on the error.
Any help would be very much so appreciated as I've been looking for solutions for this everywhere. I'm hoping it's something stupid/blindingly obvious that I somehow missed.

In order to use middleware, such as Session, Cache, etc in ASP.NET 5, you have to enable them explicitly.
Enabling session is done by adding the appropriate nuget package in your project.json file's dependencies section (make sure that the package version matches the versions of the other dependencies you have added):
"Microsoft.AspNet.Session": "1.0.0-*"
and the appropriate session (cache) storage package as well (like the example below; in memory):
"Microsoft.Extensions.Caching.Memory": "1.0.0-*"
and adding the middleware to dependency resolution in the Startup.cs Service configuration:
public void ConfigureServices(IServiceCollection services)
{
services.AddCaching();
services.AddSession(/* options go here */);
}
and adding the middleware to OWIN in the Startup.cs OWIN configuration:
public void Configure(IApplicationBuilder app)
{
app.UseSession();
//...
Make sure that the UseSession comes before the MVC configuration.

For Asp.Net Core, make sure Asp.NetCore.Session is added.
You can configure session in StartUp.cs like below.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddSingleton<ITempDataProvider, CookieTempDataProvider>();
// Adds a default in-memory implementation of IDistributedCache.
services.AddDistributedMemoryCache();
services.AddSession(options =>
{
// Set a short timeout for easy testing.
options.IdleTimeout = TimeSpan.FromSeconds(10);
options.CookieHttpOnly = true;
});
}
public void Configure(IApplicationBuilder app)
{
app.UseSession();
app.UseMvcWithDefaultRoute();
}

Related

React.NET .NET Core 3.1 Not passing props into component

I am using MVC ASP.NET Core 3.1 and React.NET and I am getting this issue.
When I render my component, the component renders, but the props are always null. It is almost as if the Html.React render method isn't properly passing the values over, please help!
I'm only going to add relevent code to the react (my startup.cs has more settings)
Startup.cs
public void ConfigureServices(IServiceCollection services) {
services.AddJsEngineSwitcher(options => options.DefaultEngineName = ChakraCoreJsEngine.EngineName).AddChakraCore();
services.AddReact();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseReact(config =>
{
// If you want to use server-side rendering of React components,
// add all the necessary JavaScript files here. This includes
// your components as well as all of their dependencies.
// See http://reactjs.net/ for more information. Example:
config
.AddScript("~/scripts/react_common/login.jsx");
config.SetLoadBabel(true);
});
}
index.cshtml (or any view, just trying to use this HTML extension helper)
#Html.React("Login", new
{
Test = "Test"
}, serverOnly: true)
login.jsx
class Login extends React.Component {
render() {
return <div>{this.props.Test}</div>
}
No matter what I do, it will never display "Test" for example. I need to know why it isn't passing the values into the props. I am starting to lose my mind over this problem, it worked just fine before I started migrating to .NET Core.
More details (Nuget Packages)
React.Asp.Net(5.1.2)
React.AspNet.Middleware(5.1.2)
Please help.
The default JSON serializer contract resolver is set to automatically convert it into camelCase (React). You have to over-ride this behavior if you want it to maintain the supplied case - in the Configure method in startup.cs:
app.UseReact(...
app.UseStaticFiles();
//Ensure to place this after the UseRact statement above
ReactSiteConfiguration.Configuration.JsonSerializerSettings.ContractResolver = new DefaultContractResolver();
Hopefully this helps someone else from going crazy

Angular 7 + dotnet core + SignalR IIS Issue

I'm trying to deploy an Angular 7/.net Core application on my local IIS and am running into an issue. I used the Angular template in Visual Studio to create a .net core backend with an Angular front-end. I also added SignalR to both projects. Here are some code samples:
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
});
services.AddSignalR();
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/dist";
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
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.UseStaticFiles();
app.UseSpaStaticFiles();
app.UseCors("CorsPolicy");
app.UseSignalR(routes =>
{
routes.MapHub<MyHub>("/myHub");
});
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");
}
});
}
connection.service.ts
if (!this.hubConnection) {
this.hubConnection = new
HubConnectionBuilder().withUrl('http://localhost:5000/myhub').build();
}
public start(): void {
this.hubConnection
.start()
.then(() => {
console.log('Connection started');
this.startingSubject.next();
})
.catch((error: any) => this.startingSubject.error(error));
}
data.component.ts
private getAllData(): Promise<Data> {
const publishDate = this.getPublishDate();
return this.connectionService.hubConnection.invoke("GetAllData",
publishDate);
}
As a quick summary, I have a connection service to handle the signalR connections on the Angular side. Essentially, app.component.ts calls the Start() method in connection.service.ts which starts the SignalR connection. data.component.ts is subscribed to this event and when the connection is successful, it calls the GetAllData() method.
I was trying to follow this tutorial in getting this set up via IIS, but can't get it to work. (https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/?view=aspnetcore-2.2)
I Publish from Visual Studio, this creates a directory with my .net Core DLL and a ClientApp folder for my Angular site. If I do a dotnet myapp.dll command I can navigate to localhost:5000 and everything works great.
localhost:5000/myhub returns a response from my signalR hub
localhost:5000/client shows the signalR client webpage perfectly
localhost:5000/host shows the signalR host webpage perfectly.
I should also note that this works when running through VS too. However, when I run through IIS, I get these results:
localhost:5000/myhub returns a response from my signalR hub
localhost:5000/client shows the signalR client webpage perfectly
localhost:5000/host fails with:
ERROR Error: Uncaught (in promise): Error: An unexpected error
occurred invoking 'GetAllData' on the server. Error: An unexpected
error occurred invoking 'GetAllData' on the server.
/Host does try to make a call to /myhub, which makes me wonder if IIS has an issue with this communicating with the same port or something. or maybe I'm just setting up IIS wrong.
Does anyone have any ideas as to how to get this working via IIS? I'm been scratching my head over this all afternoon.
Edit:
After continuing to troubleshoot, it looks like the data.component.ts is successfully calling a "Connect" method on the hub just before the "GetAllData" method.
public Data GetAllData(DateTime? publishDate)
{
... Logic here
}
PublishDate should allow nulls (in this scenario, null is actually being passed to this method), is it possible this isn't allowed for some reason? Again, i have a hard time seeing why this would work everywhere but IIS, but I'm grasping at straws that this point. Seems weird that Connect() would work but GetAllData() wouldn't when they're on the same hub.
One more edit
The more I research, the more it looks like there is an actual exception within the GetAllData() method. I'm working at verifying this but I think what's happening is that I have a file path that I'm trying to access but this file path doesn't exist when the application is built. I'm not 100% sure as to why it's failing for IIS only but I'm continuing to dig. I'll post my findings in case anyone else stumbles across this very specific issue :)
I may have missed it.. but where is your MyHub class?
Something like this:
Public class MyHub : Hub {
Public async Task GetAllData() {
*logic here for when client calls hub*
}
}

"Microsoft.Extensions.DependencyInjection" and different concretes per environment

"Microsoft.Extensions.DependencyInjection"
List of "environments"
Production
Uat
Qa
DevShared
LocalDev
With DotNet (Framework/Classic) 4.6 or above (aka, "in the past", I used "Unity" with xml configuration. https://blogs.msdn.microsoft.com/miah/2009/04/03/testing-your-unity-xml-configuration/
(In the past before Dot Net core when using "Unity" IoC/DI)...When I had a need to have a concrete specific to an environment, I would tweak the concrete on the .xml.
For instance, let's say my webApi needed authentication in production, uat, qa and dev-shared. but in dev-local, I do not want to deal with authentication all the time as I developed the webApi, I would have 2 concretes.
IAuthorizer
MyRealAuthorizer : IAuthorizer
MyDevLetEverythingThroughAuthorizer : IAuthorizer
and I would "register" one of them .. using xml.
My build process would alter the unity.xml (unity.config to be precise) and change out (via xml-update-tasks in msbuild)
MyDevLetEverythingThroughAuthorizer
to
MyRealAuthorizer
.
.....
Java Spring has "annotation" based:
import org.springframework.context.annotation.Profile;
#Profile("localdev")
public class MyDevLetEverythingThroughAuthorizer implements IAuthorizer {
#Profile("!localdev")
public class MyRealAuthorizer implements IAuthorizer {
But that does not honor the "Composite Root" pattern : (Mark Seeman http://blog.ploeh.dk/2011/07/28/CompositionRoot/ )
.......
So now I'm entering the world of DotNetCore. Everything has been going smooth. But I finally hit a situation where I need a dev-friendly concrete vs a non-dev "real" concretes.
Xml isn't available (to my best knowledge) with "Microsoft.Extensions.DependencyInjection".
I'm not sure of the best practice with DotNetCore in this situation.
I would prefer to honor the Composite Root pattern.
Basically, the below......but respecting the environments.
asp.net'ish
public void ConfigureServices(Microsoft.Extensions.DependencyInjection.IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
/* need this for "local-dev" */
services.AddScoped<IAuthorizer, MyDevLetEverythingThroughAuthorizer>();
/* need this for everything EXCEPT "local-dev" */
services.AddScoped<IAuthorizer, MyRealAuthorizer>();
}
(not asp.net) dot.net core'ish too
private static System.IServiceProvider BuildDi()
{
//setup our DI
IServiceProvider serviceProvider = new ServiceCollection()
.AddLogging()
/* need this for "local-dev" */
.AddSingleton<IAuthorizer, MyDevLetEverythingThroughAuthorizer>()
/* need this for everything EXCEPT "local-dev" */
.AddSingleton<IAuthorizer, MyRealAuthorizer>()
APPEND
This article and snipplet help me understand the "what is built in" portion a little better:
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/environments?view=aspnetcore-2.2
Environments ASP.NET Core reads the environment variable
ASPNETCORE_ENVIRONMENT at app startup and stores the value in
IHostingEnvironment.EnvironmentName. You can set
ASPNETCORE_ENVIRONMENT to any value, but three values are supported by
the framework: Development, Staging, and Production. If
ASPNETCORE_ENVIRONMENT isn't set, it defaults to Production.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
if (env.IsProduction() || env.IsStaging() || env.IsEnvironment("Staging_2"))
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseMvc();
}
The
env.IsEnvironment("Staging_2") (akin to env.IsEnvironment("MyCustomValue") ) is the trick I guess.
APPEND:
This SOF question made it more clear for Asp.Net Core.
How to set aspnetcore_environment in publish file?
And ways you can set the environment variable without actually setting a (machine) environment variable!
public void ConfigureServices(IServiceCollection services, IHostingEnvironment environment) {
if (environment.IsDevelopment()) {
// bla bla bla
} else {
// bla bla bla
}
// register no-matter-which-environment services
}
Your question seems to be talking about two things: setting configuration from XML files and managing services using IServiceCollection. For .net core web applications, these happen in two stages:
A key value pair is consolidated from various pre-defined and custom sources (including json, XML, environment). All preset .net core web templates do this in program.cs.
The key value pair collection is sent to the Startup class that can be accessed via DI from the IConfiguration variable. Check this link for more information.
With this being the process, all config files are added before the ConfigureServices method is called in the Startup class. If you would like to add XML files to this configuration, you can set the following code in your program.cs:
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
// additional code
.UseConfiguration(
new ConfigurationBuilder()
.AddXmlFile("file.xml", true) // second param is if file is optional
.Build()
)
// end of additional code
.UseStartup<Startup>();
If you want to access your environment, if they are set as environment variables, you can use one of the Environment.Get... functions.
Regarding your service, I am not sure in what way you are trying to access your XML, but you can always inject the IConfiguration as the simplest solution if you need to. However, I would advise against exposing your entire configuration to your services and have a look at setting up options with the help of this documentation

Using sessions in .net core 1

I'm trying to enable sessions in .net core webapp. I have tried following the documentation from here. But issue is the sessions are not getting persisted. With every new request new session id is generated even if previous request has stored something in session. Also I don't see any cookie in dev tools.
Referenced dlls
"Microsoft.AspNetCore.Session": "1.1.1",
"Microsoft.Extensions.Caching.Memory": "1.1.1"
My startup file looks something like this
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc(options => { options.Filters.Add(new RequireHttpsAttribute()); });
// Add services needed for sessions
services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromMinutes(10);
});
// Add in-memory distributed cache
services.AddDistributedMemoryCache();
// initialising other services, authentication and authorization policies
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
// enable session before uisng it in pipeline
app.UseSession();
// setting custom user middleware
app.UseUserMiddleware();
// set up the mvc default route
app.UseMvc(routes => { routes.MapRoute("default", "myDefaultRoute"); });
// adding few other middlewares
}
And I set and access the session values in my controller something like this
public class MyController : Controller
{
private const string Key = "someKey";
public async Task<ResponseModel> Get()
{
var id = HttpContext.Session.GetInt32(Key);
return new ResponseModel(await _myService.GetAsync(id));
}
public async Task Set([FromBody] RequestModel request)
{
var id = await _myService.GetAsync(request.id);
HttpContext.Session.SetInt32(Key, id);
}
}
In ASP.NET Core, session state is stored in distributed cache, which you've configured to be in-memory. This is basically the same as In Proc session storage in ASP.NET. Since everything stored in memory is tied to the process, whenever the process changes, your session store is wiped.
Now, it should still persist request to request, as long as you keep the application running, but particularly if you stop/start debugging in Visual Studio, you're killing and restarting the process and therefore, wiping the session.
Long and short, if you need your sessions to be persistent, you need to use a persistent store, like SQL Server or Redis. Either can be used in development just as well as in production, if you so desire. Refer to the documentation for details on how to set up a persistent store.

ASP.NET Core WebAPI 500 Internal error in IIS 7.5

I'm struggling to get this WebAPI to work. Well, work with IIS. Everything works fine in IIS express, but when I publish it, specifically 1 api request doesn't work. I'm trying to access a url of API/[Controller]/{date}/{integer}. I keep getting the 500 server error. My other route of API/[Controller]/{date} works.
Here's my API Controller:
[Route("api/[controller]")]
public class PostingsController : Controller
{
// GET: api/Postings/5
[HttpGet("{date}")]
public string Get(string date)
{
return date;
}
// GET api/Postings/20160407/2
[HttpGet("{date}/{modeID}")]
public List<TruckPosting> Get(string date, int modeID)
{
TruckPosting tp = new TruckPosting();
List<TruckPosting> truckPostings = tp.GetTruckPostings(date, modeID);
return truckPostings;
}
}
Could the reason be that I'm trying to return a List<>? I'm stumped considering it works fine in VS's IIS Express.
Edit
Here's my startup.cs page:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
}
public void Configure1(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseIISPlatformHandler();
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseFileServer(true);
app.UseMvc();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.Map("/appRoot", (app1) => this.Configure1(app1, env, loggerFactory));
}
That's a good thought that it might that fact that you're returning a List. We have working Core Web API methods and all of them return Task<IEnumerable<Foo>>. Try changing the return type List<TruckPosting> to Task<IEnumerable<TruckPosting>>
EDIT: To view the details for 500 (internal server) errors you will need to put the following line of code at the beginning of your Configure (or Configure1) method:
app.UseDeveloperExceptionPage();
And obviously this is not something you want in a production environment.
EDIT2: When running in VS you can use the code below to show exception details as long as the Hosting:Environment variable in the Debug section of Properties is set to "Development". After publishing you will need to create a System Environment variable named ASPNET_ENV and set its value to "Development" or the code will not call the UseDeveloperExceptionPage() method.
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
I posted an ASP.NET Core custom exception handler on GitHub today. I thought it might be helpful to you since you're building an SPA and are probably calling a lot Web API methods.
It's a middleware project that returns error messages for Web API calls and redirects to an error page for non Web API calls. It can also log the exceptions in a SQL Server database. That's done in a separate thread to help with performance.
The solution includes a demo application that shows how to use the exception handler for both Web API exceptions and non Web API exceptions.
Here's the link.
https://github.com/ClintBailiff/CustomExceptionHandler
If you end up checking it out and have some suggestions or comments, I like to hear them.

Categories