I am setting up Integration tests of my Web UI using abp 3.9.0.
I have followed the model at https://github.com/aspnetboilerplate/aspnet-core-template/tree/master/test/AbpCompanyName.AbpProjectName.Web.Tests
Everything compiles and executes, but I get a null reference exception at the following in my Test base class:
protected void UsingDbContext(Action<CentralPortalDbContext> action)
{
using (var context = IocManager.Resolve<CentralPortalDbContext>())
{
action(context);
context.SaveChanges();
}
}
Inspecting the function during debugging, it shows that IocManager is null.
I've tried various permutations in all of the classes with no luck.
Startup.cs:
using System;
using Abp.AspNetCore;
using Abp.AspNetCore.TestBase;
using Abp.Dependency;
using *****.CentralPortal.EntityFrameworkCore;
using *****.CentralPortal.Web.Controllers;
using Castle.MicroKernel.Registration;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using System.Collections.Generic;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using System.IdentityModel.Tokens.Jwt;
using Microsoft.AspNetCore.Authentication.Cookies;
using Abp.Reflection.Extensions;
namespace *****.CentralPortal.Web.Tests
{
public class Startup
{
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddEntityFrameworkInMemoryDatabase();
services.AddMvc()
.PartManager.ApplicationParts.Add(new AssemblyPart(typeof(Web.Startup.CentralPortalWebModule).GetAssembly()));
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie("Cookies")
.AddOpenIdConnect(options => SetOpenIdConnectOptions(options));
services = SetAuthorizations(services);
//Configure Abp and Dependency Injection
return services.AddAbp<CentralPortalWebTestModule>(options =>
{
options.SetupTest();
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
UseInMemoryDb(app.ApplicationServices);
app.UseAbp(); //Initializes ABP framework.
app.UseExceptionHandler("/Error");
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}"
);
});
app.UseAuthentication();
}
private void UseInMemoryDb(IServiceProvider serviceProvider)
{
var builder = new DbContextOptionsBuilder<CentralPortalDbContext>();
builder.UseInMemoryDatabase(Guid.NewGuid().ToString()).UseInternalServiceProvider(serviceProvider);
var options = builder.Options;
var iocManager = serviceProvider.GetRequiredService<IIocManager>();
iocManager.IocContainer
.Register(
Component.For<DbContextOptions<CentralPortalDbContext>>()
.Instance(options)
.LifestyleSingleton()
);
}
private void SetOpenIdConnectOptions(OpenIdConnectOptions options)
{
options.SignInScheme = "Cookies";
options.Authority = "http://localhost:50052";
options.RequireHttpsMetadata = false;
options.ClientId = "centralportal";
options.ClientSecret = "*************";
options.ResponseType = OpenIdConnectResponseType.CodeIdToken;
options.MetadataAddress = $"http://localhost:50052/.well-known/openid-configuration";
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("auditingApi");
options.Scope.Add("ordersApi");
options.Scope.Add("identityApi");
options.Scope.Add("offline_access");
options.Scope.Add("role");
}
//Helper method to add all authorization policies
//Keeps the ConfigureServices method cleaner.
private IServiceCollection SetAuthorizations(IServiceCollection services)
{
services.AddAuthorization(options =>
options
.AddPolicy("TestResults", builder =>
{
builder.RequireClaim("role", new List<string> { "TestResults" });
})
);
services.AddAuthorization(options =>
options
.AddPolicy("Orders", builder =>
{
builder.RequireRole(new[] { "Orders" });
})
);
services.AddAuthorization(options =>
options
.AddPolicy("HomePage", builder =>
{
builder.RequireRole(new[] { "HomePage" });
})
);
services.AddAuthorization(options =>
options
.AddPolicy("Dashboard", builder =>
{
builder.RequireRole(new[] { "Dashboard" });
})
);
services.AddAuthorization(options =>
options
.AddPolicy("UserAdmin", builder =>
{
builder.RequireRole(new[] { "UserAdmin" });
})
);
services.AddAuthorization(options =>
options
.AddPolicy("CustomerAdmin", builder =>
{
builder.RequireRole(new[] { "CustomerAdmin" });
})
);
return services;
}
}
}
WebTestBase:
using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Abp.AspNetCore.TestBase;
using *****.CentralPortal.EntityFrameworkCore;
using *****.CentralPortal.Tests.TestDatas;
using AngleSharp.Dom.Html;
using AngleSharp.Parser.Html;
using Microsoft.AspNetCore.Hosting;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Shouldly;
using Abp.Dependency;
namespace *****.CentralPortal.Web.Tests
{
public abstract class CentralPortalWebTestBase : AbpAspNetCoreIntegratedTestBase<Startup>
{
protected static readonly Lazy<string> ContentRootFolder;
//IIocManager _IocManager;
static CentralPortalWebTestBase()
{
ContentRootFolder = new Lazy<string>(WebContentDirectoryFinder.CalculateContentRootFolder, true);
}
protected CentralPortalWebTestBase() : base()
{
UsingDbContext(context => new TestDataBuilder(context).Build());
}
protected override IWebHostBuilder CreateWebHostBuilder()
{
var _ContentRootFolder = new Lazy<string>(WebContentDirectoryFinder.CalculateContentRootFolder, true);
UsingDbContext(context => new TestDataBuilder(context).Build());
return base
.CreateWebHostBuilder()
.UseStartup<Startup>()
.UseContentRoot(_ContentRootFolder.Value);
}
#region Get response
protected async Task<T> GetResponseAsObjectAsync<T>(string url,
HttpStatusCode expectedStatusCode = HttpStatusCode.OK)
{
var strResponse = await GetResponseAsStringAsync(url, expectedStatusCode);
return JsonConvert.DeserializeObject<T>(strResponse, new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
});
}
protected async Task<string> GetResponseAsStringAsync(string url,
HttpStatusCode expectedStatusCode = HttpStatusCode.OK)
{
var response = await GetResponseAsync(url, expectedStatusCode);
return await response.Content.ReadAsStringAsync();
}
protected async Task<HttpResponseMessage> GetResponseAsync(string url,
HttpStatusCode expectedStatusCode = HttpStatusCode.OK)
{
var response = await Client.GetAsync(url);
response.StatusCode.ShouldBe(expectedStatusCode);
return response;
}
#endregion
#region UsingDbContext
protected void UsingDbContext(Action<CentralPortalDbContext> action)
{
using (var context = IocManager.Resolve<CentralPortalDbContext>())
{
action(context);
context.SaveChanges();
}
}
protected T UsingDbContext<T>(Func<CentralPortalDbContext, T> func)
{
T result;
using (var context = IocManager.Resolve<CentralPortalDbContext>())
{
result = func(context);
context.SaveChanges();
}
return result;
}
protected async Task UsingDbContextAsync(Func<CentralPortalDbContext, Task> action)
{
using (var context = IocManager.Resolve<CentralPortalDbContext>())
{
await action(context);
await context.SaveChangesAsync(true);
}
}
protected async Task<T> UsingDbContextAsync<T>(Func<CentralPortalDbContext, Task<T>> func)
{
T result;
using (var context = IocManager.Resolve<CentralPortalDbContext>())
{
result = await func(context);
context.SaveChanges();
}
return result;
}
#endregion
#region ParseHtml
protected IHtmlDocument ParseHtml(string htmlString)
{
return new HtmlParser().Parse(htmlString);
}
#endregion
}
}
Web Test Module
using Abp.AspNetCore.TestBase;
using Abp.Modules;
using Abp.Reflection.Extensions;
using Castle.MicroKernel.Registration;
using Castle.Windsor.MsDependencyInjection;
using *****.CentralPortal.EntityFrameworkCore;
using *****.CentralPortal.Web.Startup;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
namespace *****.CentralPortal.Web.Tests
{
[DependsOn(
typeof(CentralPortalWebModule),
typeof(CentralPortalEntityFrameworkCoreModule),
typeof(AbpAspNetCoreTestBaseModule)
)]
public class CentralPortalWebTestModule : AbpModule
{
public override void PreInitialize()
{
Configuration.UnitOfWork.IsTransactional = false; //EF Core InMemory DB does not support transactions.
}
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(typeof(CentralPortalWebTestModule).GetAssembly());
SetupInMemoryDb();
}
private void SetupInMemoryDb()
{
var services = new ServiceCollection()
.AddEntityFrameworkInMemoryDatabase();
var serviceProvider = WindsorRegistrationHelper.CreateServiceProvider(
IocManager.IocContainer,
services
);
var builder = new DbContextOptionsBuilder<CentralPortalDbContext>();
builder.UseInMemoryDatabase().UseInternalServiceProvider(serviceProvider);
IocManager.IocContainer.Register(
Component
.For<DbContextOptions<CentralPortalDbContext>>()
.Instance(builder.Options)
.LifestyleSingleton()
);
}
}
}
Web Test Class:
using System.Threading.Tasks;
using *****.CentralPortal.Web.Controllers;
using Shouldly;
using Xunit;
namespace *****.CentralPortal.Web.Tests.Controllers
{
public class HomeController_Tests: CentralPortalWebTestBase
{
[Fact]
public async Task Index_Test()
{
string url = GetUrl<HomeController>(nameof(HomeController.Index));
//Act
var response = await GetResponseAsStringAsync(
url
);
//Assert
response.ShouldNotBeNullOrEmpty();
}
[Fact]
public async void ShouldOnlyShowHomeMenuWhenNotAuthorized()
{
var response = await GetResponseAsStringAsync(
GetUrl<HomeController>(nameof(HomeController.Index))
);
//Parse the response for menuitems, count them and assert
int menuitemcount = 0;
string statuscode = "";//TODO: Gotta parse the response string to get the code
Assert.Equal(menuitemcount, 2);
}
}
}
I'm not sure why IocManager is null at this point. I'm guessing it's a simple config item I'm missing, but I can't seem to find it or any examples that deviate from what I've got.
Any help would be appreciated.
As Requested: the Full Exception.
[1/29/2019 8:51:46 AM Informational] [xUnit.net 00:00:02.72] System.NullReferenceException : Object reference not set to an instance of an object.
[1/29/2019 8:51:46 AM Informational] [xUnit.net 00:00:02.72] Stack Trace:
[1/29/2019 8:51:46 AM Informational] [xUnit.net 00:00:02.72] C:\ProjectCode\*****\*****_CentralPortal\test\*****.CentralPortal.Web.Tests\CentralPortalWebTestBase.cs(78,0): at *****.CentralPortal.Web.Tests.CentralPortalWebTestBase.UsingDbContext(Action`1 action)
[1/29/2019 8:51:46 AM Informational] [xUnit.net 00:00:02.72] C:\ProjectCode\*****\*****_CentralPortal\test\*****.CentralPortal.Web.Tests\CentralPortalWebTestBase.cs(37,0): at *****.CentralPortal.Web.Tests.CentralPortalWebTestBase.CreateWebHostBuilder()
[1/29/2019 8:51:46 AM Informational] [xUnit.net 00:00:02.72] D:\Github\aspnetboilerplate\src\Abp.AspNetCore.TestBase\AbpAspNetCoreIntegratedTestBase.cs(30,0): at Abp.AspNetCore.TestBase.AbpAspNetCoreIntegratedTestBase`1..ctor()
[1/29/2019 8:51:46 AM Informational] [xUnit.net 00:00:02.72] C:\ProjectCode\*****\*****_CentralPortal\test\*****.CentralPortal.Web.Tests\CentralPortalWebTestBase.cs(28,0): at *****.CentralPortal.Web.Tests.CentralPortalWebTestBase..ctor()
[1/29/2019 8:51:46 AM Informational] [xUnit.net 00:00:02.72] at *****.CentralPortal.Web.Tests.Controllers.HomeController_Tests..ctor()
So it was the following in the web test module. I'm not sure where I got that from, I think it was in an example I pulled from. Commenting out SetupInMemoryDb(); resolved the issue.
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(typeof(CentralPortalWebTestModule).GetAssembly());
SetupInMemoryDb();
}
private void SetupInMemoryDb()
{
var services = new ServiceCollection()
.AddEntityFrameworkInMemoryDatabase();
var serviceProvider = WindsorRegistrationHelper.CreateServiceProvider(
IocManager.IocContainer,
services
);
var builder = new DbContextOptionsBuilder<CentralPortalDbContext>();
builder.UseInMemoryDatabase().UseInternalServiceProvider(serviceProvider);
IocManager.IocContainer.Register(
Component
.For<DbContextOptions<CentralPortalDbContext>>()
.Instance(builder.Options)
.LifestyleSingleton()
);
}
Related
When using InMemoryMessageScheduler with Quartz, the ScheduledMessage actually gets scheduled and the "Message" is published at the defined time.
The problem is when the Quartz with persisting option is used, the message is persisted into the database, the ScheduledMessage is consumed by the ScheduleMessageConsumer BUT the "Message" is never published at the defined time.
I've used Sample-GettingStarted and I've added the next changes:
QuartzConfig:
public class QuartzConfig : Dictionary<string, string>
{
public QuartzConfig(string connectionString)
{
this["quartz.scheduler.instanceName"] = "MassTransit-Scheduler";
this["quartz.scheduler.instanceId"] = "AUTO";
this["quartz.serializer.type"] = "json";
this["quartz.jobStore.type"] = "Quartz.Impl.AdoJobStore.JobStoreTX, Quartz";
this["quartz.jobStore.driverDelegateType"] = "Quartz.Impl.AdoJobStore.StdAdoDelegate, Quartz";
this["quartz.jobStore.tablePrefix"] = "QRTZ_";
this["quartz.jobStore.dataSource"] = "myDS";
this["quartz.dataSource.myDS.provider"] = "Npgsql";
this["quartz.dataSource.myDS.connectionString"] = connectionString;
this["quartz.jobStore.useProperties"] = "true";
}
public NameValueCollection ToNameValueCollection()
{
return this.Aggregate(new NameValueCollection(), (seed, current) =>
{
seed.Add(current.Key, current.Value);
return seed;
});
}
}
Configuration:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
services.AddMassTransit(x =>
{
x.AddConsumer<MessageConsumer>();
var scheduler = CreateScheduler();
x.UsingRabbitMq((context,cfg) =>
{
cfg.ReceiveEndpoint("quartz", endpoint =>
{
endpoint.Consumer(() => new ScheduleMessageConsumer(scheduler));
endpoint.Consumer(() => new CancelScheduledMessageConsumer(scheduler));
cfg.UseMessageScheduler(endpoint.InputAddress);
});
cfg.ConfigureEndpoints(context);
});
});
services.AddMassTransitHostedService();
services.AddHostedService<Worker>();
});
static IScheduler CreateScheduler()
{
var dbConnectionString = "Host=localhost;Database=scheduler;Port=5432;Password=pass;User ID=user;Pooling=true;MaxPoolSize=200;Enlist=true";
var quartzConfig = new QuartzConfig(dbConnectionString)
.ToNameValueCollection();
ISchedulerFactory schedulerFactory = new StdSchedulerFactory(quartzConfig);
return schedulerFactory.GetScheduler().GetAwaiter().GetResult();
}
Worker.cs:
public class Worker : BackgroundService
{
readonly IBus _bus;
public Worker(IBus bus)
{
_bus = bus;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
await _bus.CreateMessageScheduler().SchedulePublish(DateTime.UtcNow + TimeSpan.FromSeconds(5), new Message { Text = $"I really hope this is scheduled {DateTime.Now}" });
await Task.Delay(10000, stoppingToken);
}
}
}
Any ideas?
The Quartz Integration package connects a bus observer to handle the start/stop of Quartz.NET, as shown in the source. Unfortunately the documentation isn't great on how to do it.
I have been using embedio and I would like to post pdf and display it in my Webview in my xamarin application. The pdf is as embedded resource in my application. It all seems to be ok, but the stream position is 0, however the status is 200 ok. and then At readTimeout I see
System.InvalidOperationException: Timeouts are not supported on this stream.
at System.IO.Stream.get_ReadTimeout () [0x00000] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/external/corert/src/System.Private.CoreLib/shared…
My initialization of embedio
public App()
{
Task.Factory.StartNew(async () =>
{
using (var server = new WebServer(HttpListenerMode.EmbedIO, "http://*:8089"))
{
Assembly assembly = typeof(App).Assembly;
server.WithLocalSessionManager();
server.WithWebApi("/api", m => m.WithController(() => new PdfSourceController()));
server.WithEmbeddedResources("/", assembly, "TestApp.html");
await server.RunAsync();
}
});
MainPage = new NavigationPage(new MainPage());
}
My controller
public class PdfSourceController : WebApiController
{
public PdfSourceController() : base()
{
}
[Route(HttpVerbs.Post, "/pdf")]
public async Task UploadFile()
{
var parser = new MultipartFormDataContent();
var fileContent = new StreamContent(new EmbeddedResourceDataStream("Assets/TestDoc.pdf").GetDataStream());
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{Name = "result", FileName = $"\"{"test"}\""};
fileContent.Headers.ContentType = new MediaTypeHeaderValue("multipart/form-data");
parser.Add(fileContent);
}
private async Task TestPost()
{
try
{
var handler = new HttpClientHandler
{
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate ,
};
using (var client = new HttpClient(handler))
{
client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("*"));
using (var response = await client.PostAsync($"{DefaultUrl}api/pdf", new MultipartFormDataContent() ).ConfigureAwait(false)) // calling controller?
{
response.Content.Headers.ContentType = new MediaTypeHeaderValue("api/pdf"); // stating what media type?
var responseString = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
response.Content = new StreamContent(responseString);
Pdf = ImageSource.FromStream(() => responseString);
}
}
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
I'm trying to get my feet wet with Xamarin and I'm having trouble adding in my organization's login. The screen shot below is as far as I can get attempting to login. When I click "Continue" the same page just loads again. Not really sure what's going on.
The image is the screen I'm stuck on.
I've added code that represents the app class and the code behind for the XAML page attempting to login, leaving out what I "think" is irrelvant.
Any suggestions?
public partial class App : Application
{
public static string AzureBackendUrl =
DeviceInfo.Platform == DevicePlatform.Android ? "http://10.0.2.2:5000" : "http://localhost:5000";
public static bool UseMockDataStore = true;
public static IPublicClientApplication PCA = null;
public static string ClientID = "CLIENT_ID";
public static string[] Scopes = { "User.Read" };
public static string Username = string.Empty;
public static object ParentWindow { get; set; }
public App()
{
InitializeComponent();
if (UseMockDataStore)
DependencyService.Register<MockDataStore>();
else
DependencyService.Register<AzureDataStore>();
PCA = PublicClientApplicationBuilder.Create(ClientID)
.WithRedirectUri($"msal{App.ClientID}://auth")
//.WithParentActivityOrWindow(() => App.ParentWindow)
.Build();
MainPage = new MSAL_Example();
}
}
public partial class MSAL_Example : ContentPage
{
public static string tenant_name = "MY_TENANT_NAME";
public MSAL_Example()
{
InitializeComponent();
App.ParentWindow = this;
}
public async Task SignOutAsync()
{
IEnumerable<IAccount> accounts = await App.PCA.GetAccountsAsync();
try
{
while (accounts.Any())
{
await App.PCA.RemoveAsync(accounts.FirstOrDefault());
accounts = await App.PCA.GetAccountsAsync();
}
slUser.IsVisible = false;
Device.BeginInvokeOnMainThread(() => { btnSignInSignOut.Text = "Sign in"; });
}
catch (Exception ex)
{
Debug.WriteLine("\tERROR {0}", ex.Message);
}
}
public async Task SignInAsync()
{
AuthenticationResult authResult = null;
IEnumerable<IAccount> accounts = await App.PCA.GetAccountsAsync();
// let's see if we have a user in our belly already
try
{
IAccount firstAccount = accounts.FirstOrDefault();
authResult = await App.PCA.AcquireTokenSilent(App.Scopes, firstAccount)
.ExecuteAsync();
await RefreshUserDataAsync(authResult.AccessToken).ConfigureAwait(false);
Device.BeginInvokeOnMainThread(() => { btnSignInSignOut.Text = "Sign out"; });
}
catch (MsalUiRequiredException ex)
{
try
{
authResult = await App.PCA.AcquireTokenInteractive(App.Scopes)
.WithParentActivityOrWindow(App.ParentWindow)
.WithAuthority("https://login.microsoftonline.com/" + tenant_name)
.ExecuteAsync();
await RefreshUserDataAsync(authResult.AccessToken);
Device.BeginInvokeOnMainThread(() => { btnSignInSignOut.Text = "Sign out"; });
}
catch (Exception ex2)
{
Debug.WriteLine("\tERROR {0}", ex2.Message);
}
}
}
public async Task RefreshUserDataAsync(string token)
{
//get data from API
HttpClient client = new HttpClient();
HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Get, "https://graph.microsoft.com/v1.0/me");
message.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("bearer", token);
HttpResponseMessage response = await client.SendAsync(message);
string responseString = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
JObject user = JObject.Parse(responseString);
slUser.IsVisible = true;
Device.BeginInvokeOnMainThread(() =>
{
lblDisplayName.Text = user["displayName"].ToString();
lblGivenName.Text = user["givenName"].ToString();
lblId.Text = user["id"].ToString();
lblSurname.Text = user["surname"].ToString();
lblUserPrincipalName.Text = user["userPrincipalName"].ToString();
// just in case
btnSignInSignOut.Text = "Sign out";
});
}
else
{
await DisplayAlert("Something went wrong with the API call", responseString, "Dismiss");
}
}
}
I'm trying to save my session in ASP.NET Core, but it is not getting saved.
I have looked at other answers, suggesting to change CookiePolicyOptions and nothing has worked so far. I have another project with the exact same code (presumably), and it works there but not in this project.
In my controller I have:
[HttpPost]
public IActionResult AddToPlan(int mealId)
{
PlanCart planCart = GetPlanCart();
planCart.AddItem(mealId);
SavePlanCart(planCart);
// ALWAYS 1
var y = planCart.returnList();
foreach (var x in y)
{
var z = x; // For debug purposes
}
return RedirectToAction("Index");
}
private PlanCart GetPlanCart()
{
PlanCart planCart = HttpContext.Session.GetJson<PlanCart>("PlanCart") ?? new PlanCart();
return planCart;
}
private void SavePlanCart(PlanCart planCart)
{
HttpContext.Session.SetJson("PlanCart", planCart);
}
I have a class with extension methods:
public static class SessionsExtensions
{
public static void SetJson(this ISession session, string key, object value)
{
session.SetString(key, JsonConvert.SerializeObject(value));
}
public static T GetJson<T>(this ISession session, string key)
{
var sessionData = session.GetString(key);
return sessionData == null
? default(T) : JsonConvert.DeserializeObject<T>(sessionData);
}
}
Startup class:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAuthentication();
app.UseSession();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
app.UseCookiePolicy();
}
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddSession();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddMemoryCache();
I have checked my session. The session DOES exist but every time the count of the PlanCartList is 1 and previous items are lost.
If anybody could help me it would be very much appreciated because I'm losing my mind here!
I have added WebApi to an existing MVC app and create a controller with a post method. I have one route configured in the webapiconfig. When I use Fiddler to post to the controller, I am receiving the "Multiple Actions" error. my ApiConfig and Controller are posted below. There is some Ioc and DI going on with Ninject. Do I need to add different routes definitions, or is this about the data being posted?
webapiconfig.cs
public static void Register(HttpConfiguration config)
{
var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
config.Routes.MapHttpRoute(
name: "Materials",
routeTemplate: "api/materials/{id}",
defaults: new { controller = "materials", id = RouteParameter.Optional }
);
}
MaterialController.
using ????.Info.DAL;
using ????.Info.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using IdentitySample.Models;
namespace ????.Info.Controllers.Api
{
public class MaterialsController : BaseApiController
{
public MaterialsController(I????Repository repo)
:base(repo)
{
}
[Route("api/materials/")]
public IEnumerable<MaterialModel> Get()
{
IQueryable<MaterialEntities.Materials> query;
query = TheRepository.GetAllMaterials();
var results = query
.ToList()
.Select(s => TheModelFactory.Create(s));
return results;
}
[Route("api/materials/{id:int}")]
public HttpResponseMessage GetMaterial(int id)
{
try
{
var material = TheRepository.GetMaterial(id);
if (material != null)
{
return Request.CreateResponse(HttpStatusCode.OK, TheModelFactory.Create(material));
}
else
{
return Request.CreateResponse(HttpStatusCode.NotFound);
}
}
catch (Exception ex)
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex);
}
}
[HttpPost]
public HttpResponseMessage Post([FromBody] MaterialModel materialModel)
{
try
{
var entity = TheModelFactory.Parse(materialModel);
if (entity == null) Request.CreateErrorResponse(HttpStatusCode.BadRequest, "Could not read MaterialType/Organization from body");
if (TheRepository.Insert(entity) && TheRepository.SaveAll())
{
return Request.CreateResponse(HttpStatusCode.Created, TheModelFactory.Create(entity));
}
else
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, "Could not save to the database.");
}
}
catch (Exception ex)
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex);
}
}
public MaterialEntities.Materials Parse(MaterialModel materialmodel)
{
try
{
var material = new MaterialEntities.Materials()
{
Name = materialmodel.Name,
Description = materialmodel.Description,
DateCreated = materialmodel.DateCreated,
};
return material;
}
catch (Exception)
{
return null;
}
}
}
}
Ok, thanks for all the help on this. This was fixed by adding config.MapHttpAttributeRoutes(); to the WebApiConfig. I removed the default route definitions since I am going to use AttributeRouting and it's working now.
update: It looks like it is possible to mix Attribute and Convention routing in the WebApiConfig as discussed here So my problem was solved by adding config.MapHttpAttributeRoutes(); to WebApiConfig