Related
After an update of Visual Studio 2022 to v17.2.2, I suddenly get an error in my ASP.NET app, that a virtual class cannot insert into SQL database because the class does not allow nulls. Before the update I was not getting this error.
This is the model a use
public class Member
{
public int MemberId { get; set; }
[Required(ErrorMessage = "Dit is een verplicht veld")]
public string FirstName { get; set; }
[Required(ErrorMessage = "Dit is een verplicht veld")]
public string LastName { get; set; }
public string MemberImage { get; set; }
public Gender Gender { get; set; }
public int TeamId { get; set; }
public virtual Team Team { get; set; } = new();
}
I need the last virtual property to get all members from the database of a the Team model from the MemberRepository
public async Task<IEnumerable<Member>> GetAllMembersByTeamId(int TeamId)
{
var result = await dbContext.Members
.Include(t => t.Team)
.Where(t => t.TeamId == TeamId)
.ToListAsync();
if (result != null)
{
return result;
}
else
return null;
}
And with the a MemberRepository I store it into the database:
public class MemberRepository : IMemberRepository
{
private readonly AppDbContext dbContext;
public MemberRepository(AppDbContext dbContext)
{
this.dbContext = dbContext;
}
public async Task<Member> AddMember(Member obj)
{
await dbContext.Members.AddAsync(obj);
await dbContext.SaveChangesAsync();
return obj;
}
}
I ask for the team I want to add the member with:
protected async override Task OnInitializedAsync()
{
Team = await TeamsRepository.GetTeamById(int.Parse(Id));
}
and fired it up with the EditForm, OnValidSubmit.
public async Task HandleValidSubmit()
{
ConfirmationTitle = StaticString.ConfirmationTitle;
ConfirmationMessage = StaticString.ConfirmationMessage;
Member.TeamId = int.Parse(Id);
await MemberRepository.AddMember(Member);
NavigationManager.NavigateTo("/adminpage");
}
I'm confused, is it because the update or is something else, because I get the error also now in the previous made ASP.NET application.
Why this approach? I learned it of Kudvenkat from this site: https://www.pragimtech.com/blog/blazor/blazor-model-classes/
This is the error:
Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
This is the error i get:
blazor.server.js:1 [2022-06-02T13:13:22.000Z] Error: Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
---> Microsoft.Data.SqlClient.SqlException (0x80131904): Cannot insert the value NULL into column 'Class', table 'Tjoba-Server.dbo.Teams'; column does not allow nulls. INSERT fails.
The statement has been terminated.
The statement has been terminated.
at Microsoft.Data.SqlClient.SqlCommand.<>c.b__188_0(Task1 result) at System.Threading.Tasks.ContinuationResultTaskFromResultTask2.InnerInvoke()
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)
--- End of stack trace from previous location ---
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
ClientConnectionId:2df86c5d-9cee-4c70-ad12-ebb86a036fe9
Error Number:515,State:2,Class:16
--- End of inner exception stack trace ---
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList1 entriesToSave, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func4 operation, Func4 verifySucceeded, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at DataAcces.Data.MemberRepository.AddMember(Member obj) in C:\VsProjects\Tjoba_Server\DataAccess\Data\MemberRepository.cs:line 21
at Tjoba.Pages.Admin.AddMember.HandleValidSubmit() in C:\VsProjects\Tjoba_Server\Tjoba\Pages\Admin\AddMember.razor:line 207
at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task)
at Microsoft.AspNetCore.Components.Forms.EditForm.HandleSubmitAsync()
at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task)
at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle, ComponentState owningComponentState)
log # blazor.server.js:1
blazor.server.js:1 [2022-06-02T13:13:22.001Z] Information: Connection disconnected.
Uncaught (in promise) Error: Cannot send data if the connection is not in the 'Connected' State.
at bt.send (blazor.server.js:1:52004)
at kt._sendMessage (blazor.server.js:1:68639)
at kt._sendWithProtocol (blazor.server.js:1:68680)
at kt.send (blazor.server.js:1:68788)
at Object.beginInvokeDotNetFromJS (blazor.server.js:1:131279)
at w (blazor.server.js:1:2164)
at C.invokeMethodAsync (blazor.server.js:1:4014)
at blazor.server.js:1:11516
at T (blazor.server.js:1:11694)
at I (blazor.server.js:1:11485)
I get with a try catch block the same error message
Cannot insert the value NULL into column 'Class', table 'TjobaServer.dbo.Teams'; column does not allow nulls. INSERT fails. The statement has been terminated.
Strange is that I only want to insert a member to the database with a TeamId, but nothing to the table Teams.
I figured out and found the solution.
Have added an if block with the Entity unchanged code into the AddMember Task in the MemberRepository:
public async Task<Member> AddMember(Member member)
{
if (member.Team != null)
{
dbContext.Entry(member.Team).State = EntityState.Unchanged;
}
var result = await dbContext.Memberss.AddAsync(member);
await dbContext.SaveChangesAsync();
return result.Entity;
}
From what I can tell the best way to get the Azure MySql In App Database connection string is to read the MYSQLCONNSTR_localdb environment variable. I am just experimenting right now.
I am using .NET 6, Entity Framework 6, and MYSQL. I have a Mysql 5.7 db setup on my local computer, which I can tell is the same version that Azure MySql In App Database uses.
I have created a DbContext class and an Items DbSet from an Item Db model. I created the database and table using PhpMyAdmin through Azure, so I know that at least PHPMyAdmin is working. I also created the database and Item table in my local MySql database using the MySQL workbench. Everything works on my local computer / debugging with IIS express. For convenience sake I am just using a right-click publish to publish this app to Azure. The deploy does go well. And the site works until I try to interact with the database. I created a link to the /Items/Index page in my menu for convenience. But it tells me that it cannot connect to the SQL server. I even have added the connnection string to a ViewBag property on a page to be sure that it is reading the MYSQLCONNSTR_localdb environment variable correctly. So I am not sure what I am doing wrong.
The specific errors that I receive are:
MySqlException: Unable to connect to any of the specified MySQL hosts.
MySqlConnector.Core.ServerSession.ConnectAsync(ConnectionSettings cs, MySqlConnection connection, int startTickCount, ILoadBalancer loadBalancer, IOBehavior ioBehavior, CancellationToken cancellationToken) in ServerSession.cs
MySqlConnector.Core.ConnectionPool.ConnectSessionAsync(MySqlConnection connection, string logMessage, int startTickCount, IOBehavior ioBehavior, CancellationToken cancellationToken) in ConnectionPool.cs
System.Threading.Tasks.ValueTask.get_Result()
System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable+ConfiguredValueTaskAwaiter.GetResult()
MySqlConnector.Core.ConnectionPool.GetSessionAsync(MySqlConnection connection, int startTickCount, IOBehavior ioBehavior, CancellationToken cancellationToken) in ConnectionPool.cs
MySqlConnector.Core.ConnectionPool.GetSessionAsync(MySqlConnection connection, int startTickCount, IOBehavior ioBehavior, CancellationToken cancellationToken) in ConnectionPool.cs
System.Threading.Tasks.ValueTask.get_Result()
System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable+ConfiguredValueTaskAwaiter.GetResult()
MySqlConnector.MySqlConnection.CreateSessionAsync(ConnectionPool pool, int startTickCount, Nullable ioBehavior, CancellationToken cancellationToken) in MySqlConnection.cs
System.Threading.Tasks.ValueTask.get_Result()
System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable+ConfiguredValueTaskAwaiter.GetResult()
MySqlConnector.MySqlConnection.OpenAsync(Nullable ioBehavior, CancellationToken cancellationToken) in MySqlConnection.cs
Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenInternalAsync(bool errorsExpected, CancellationToken cancellationToken)
Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenInternalAsync(bool errorsExpected, CancellationToken cancellationToken)
Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenAsync(CancellationToken cancellationToken, bool errorsExpected)
Pomelo.EntityFrameworkCore.MySql.Storage.Internal.MySqlRelationalConnection.OpenAsync(CancellationToken cancellationToken, bool errorsExpected)
Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable+AsyncEnumerator.InitializeReaderAsync(AsyncEnumerator enumerator, CancellationToken cancellationToken)
Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy+<>c__DisplayClass33_0<TState, TResult>+<b__0>d.MoveNext()
Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.ExecuteImplementationAsync<TState, TResult>(Func<DbContext, TState, CancellationToken, Task<ExecutionResult>> operation, Func<DbContext, TState, CancellationToken, Task<ExecutionResult>> verifySucceeded, TState state, CancellationToken cancellationToken)
and
RetryLimitExceededException: The maximum number of retries (3) was exceeded while executing database operations with 'MySqlRetryingExecutionStrategy'. See the inner exception for the most recent failure.
Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.ExecuteImplementationAsync<TState, TResult>(Func<DbContext, TState, CancellationToken, Task<ExecutionResult>> operation, Func<DbContext, TState, CancellationToken, Task<ExecutionResult>> verifySucceeded, TState state, CancellationToken cancellationToken)
Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.ExecuteAsync<TState, TResult>(TState state, Func<DbContext, TState, CancellationToken, Task> operation, Func<DbContext, TState, CancellationToken, Task<ExecutionResult>> verifySucceeded, CancellationToken cancellationToken)
Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable+AsyncEnumerator.MoveNextAsync()
Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync(IQueryable source, CancellationToken cancellationToken)
Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync(IQueryable source, CancellationToken cancellationToken)
WebApplication22.Controllers.ItemsController.Index() in ItemsController.cs
Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor+TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, object controller, object[] arguments)
System.Threading.Tasks.ValueTask.get_Result()
System.Runtime.CompilerServices.ValueTaskAwaiter.GetResult()
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask actionResultValueTask)
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
Here is the relevant portion of my Program.cs (using new .net 6 style of "main" method)
builder.Services.AddDbContextPool<MyDbContext>(opt =>
{
opt.UseMySql(
System.Environment.GetEnvironmentVariable("MYSQLCONNSTR_localdb"),
new MySqlServerVersion(new Version(5, 7, 9)),
mySqlOptions =>
{
mySqlOptions.EnableRetryOnFailure(3, TimeSpan.FromSeconds(5), null);
});
});
MyDbContext class:
public class MyDbContext : Microsoft.EntityFrameworkCore.DbContext
{
public DbSet<DbModels.Item> Items { get; set; }
public MyDbContext(DbContextOptions<MyDbContext> dbConfiguration) : base(dbConfiguration)
{
}
}
Package references:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="6.0.1" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="6.0.0" />
</ItemGroup>
</Project>
Items Controller using Dependency Injection...
public class ItemsController : Controller
{
private readonly MyDbContext _context;
public ItemsController(MyDbContext context)
{
_context = context;
}
// GET: Items
public async Task<IActionResult> Index()
{
return View(await _context.Items.ToListAsync());
}
// GET: Items/Details/5
public async Task<IActionResult> Details(int? id)
{
if (id == null)
{
return NotFound();
}
var item = await _context.Items
.FirstOrDefaultAsync(m => m.Id == id);
if (item == null)
{
return NotFound();
}
return View(item);
}
// GET: Items/Create
public IActionResult Create()
{
return View();
}
// POST: Items/Create
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,Name")] Item item)
{
if (ModelState.IsValid)
{
_context.Add(item);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(item);
}
// GET: Items/Edit/5
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var item = await _context.Items.FindAsync(id);
if (item == null)
{
return NotFound();
}
return View(item);
}
// POST: Items/Edit/5
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("Id,Name")] Item item)
{
if (id != item.Id)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(item);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!ItemExists(item.Id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(item);
}
// GET: Items/Delete/5
public async Task<IActionResult> Delete(int? id)
{
if (id == null)
{
return NotFound();
}
var item = await _context.Items
.FirstOrDefaultAsync(m => m.Id == id);
if (item == null)
{
return NotFound();
}
return View(item);
}
// POST: Items/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(int id)
{
var item = await _context.Items.FindAsync(id);
_context.Items.Remove(item);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
private bool ItemExists(int id)
{
return _context.Items.Any(e => e.Id == id);
}
}
I have a problem with the post method in my register.service.ts as it should return 200 OK, but instead, it returns 405 method not allowed. I am struggling with this error for some time and I know it because I have to allow it in the header configuration and CORS middleware. I have created a middleware class which I pass it in startup.cs along with other CORS configuration as follows:
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.AddDbContext<DataContext>(options => options.UseMySql(Configuration.GetConnectionString("DataContext")));
services.AddControllersWithViews();
services.AddApiVersioning(options =>
{
options.UseApiBehavior = false;
options.AssumeDefaultVersionWhenUnspecified = true;
});
services.AddCors(options =>
{
options.AddPolicy(MyAllowSpecificOrigins,
builder => builder.WithOrigins("http://localhost:5001").AllowAnyHeader().AllowAnyMethod());
// In production, the Angular files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/dist/";
});
});
services.AddScoped(typeof(IUserService<>), typeof(UserService<>));
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
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.UseOptions();//this is the method from the CORS middleware class
app.UseRouting();
app.UseCors(MyAllowSpecificOrigins);
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");
}
});
}
}
This is the register.service.ts:
import { Injectable } from '#angular/core';
import { HttpClient, HttpClientModule, HttpHeaders } from '#angular/common/http';
import { environment } from 'src/environments/environment'; import { Register } from '../Models/register';
import { Observable, throwError } from 'rxjs';
import { retry, catchError } from 'rxjs/operators';
#Injectable({
providedIn: 'root'
})
export class RegisterService {
baseurl = 'https://localhost:5001';
constructor(private http: HttpClient) { }
Create(user): Observable<Register> {
const httpOptions = { headers: new HttpHeaders({ 'Content-Type':
'application/x-www-form-urlencoded', 'Access-Control-Allow-Headers': 'Authorization',
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS'})};
return this.http.post<Register>(this.baseurl + '/register', JSON.stringify(user),
httpOptions).pipe(retry(1), catchError(this.errorHandler));
}
GetById(id: number) {
let reqHeader = new HttpHeaders();
return this.http.post(this.baseurl + '/register/' + id , {headers: reqHeader});
}
GetAll() {
let reqHeader = new HttpHeaders();
return this.http.get(this.baseurl + '/register/', {headers: reqHeader});
}
Update(user: Register) {
let reqHeader = new HttpHeaders();
return this.http.post(this.baseurl + '/register/editUser', user, {headers: reqHeader});
}
Delete(id: number) {
let reqHeader = new HttpHeaders();
return this.http.get(this.baseurl + '/register/deleteUser/' + id, {headers: reqHeader});
}
errorHandler(error) {
let errorMessage = '';
if (error.error instanceof ErrorEvent) {
// Get client-side error
errorMessage = error.error.message;
} else {
// Get server-side error
errorMessage = `Error Code: ${error.status}\nMessage: ${error.message}`;
}
console.log(errorMessage);
return throwError(errorMessage);
}
}
I have also replaced the x-www-form-urlencoded with application/json but it has the same behaviour both in the browser and Postman.
This is the RegisterController.cs class:
[EnableCors]
[Produces("application/json")]
[Route("[controller]")]
[ApiController]
public class RegisterController : ControllerBase
{
private readonly DataContext _context;
private readonly IUserService<Register> _repo;
public RegisterController(DataContext context,IUserService<Register> repo)
{
_context = context;
_repo=repo;
}
// GET: api/Register
[HttpGet]
public async Task<ActionResult<IEnumerable<Register>>> Getregistrations()
{
return await _context.register.ToListAsync();
}
// GET: api/Register/5
[HttpGet("{id}")]
public async Task<ActionResult<Register>> GetRegister([FromRoute]int id)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var user = await _context.register.FindAsync(id);
if (user == null)
{
return NotFound();
}
return Ok(user);
}
// PUT: api/Register/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see https://aka.ms/RazorPagesCRUD.
[HttpPut("{id}")]
public async Task<IActionResult> PutRegister([FromRoute]int id,[FromBody] Register register)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (id != register.Id)
{
return BadRequest();
}
_context.Entry(register).State = EntityState.Modified;
try
{
_repo.Update(register);
var save = await _repo.SaveAsync(register);
}
catch (DbUpdateConcurrencyException)
{
if (!RegisterExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
// POST: api/Register
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see https://aka.ms/RazorPagesCRUD.
[Route("PostRegister")]
[HttpPost]
[HttpOptions]
public async Task<ActionResult<Register>> PostRegister([FromBody] Register register)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
_repo.Add(register);
var save = await _repo.SaveAsync(register);
return CreatedAtAction(nameof(GetRegister), new { id = register.Id }, register);
}
// DELETE: api/Register/5
[HttpDelete("{id}")]
public async Task<ActionResult<Register>> DeleteRegister([FromRoute]int id)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var user = await _context.register.FindAsync(id);
if (user == null)
{
return NotFound();
}
_repo.Delete(user);
var save = await _repo.SaveAsync(user);
return Ok(user);
}
private bool RegisterExists(int id)
{
return _context.register.Any(e => e.Id == id);
}
}
I have no idea why it's not working. Can someone please help me figure it out? Please let me know if you need more details.
UPDATE:
I have tried what sam suggested and I get the same result as before:
This is in Postman:
Postman result for POST
And this is from the browser:
Browser result
UPDATE 2: After trying with [FromForm] instead of [FromBody] with application/json as header:
for https://localhost:5001/register get same error 405
for https://localhost:5001/register/PostRegister getting 500
for register/PostRegister
I forgot to specify that my route path is configured to https://localhost:5001/Add
STACKTRACE:
fail: Microsoft.EntityFrameworkCore.Database.Command[20102]
Failed executing DbCommand (53ms) [Parameters=[#p0='?' (Size = 4000), #p1='?' (Size = 4000), #p2='?' (Size = 4000)], CommandType='Text', CommandTimeout='30']
INSERT INTO `register` (`Email`, `Name`, `Password`)
VALUES (#p0, #p1, #p2);
SELECT `Id`
FROM `register`
WHERE ROW_COUNT() = 1 AND `Id` = LAST_INSERT_ID();
fail: Microsoft.EntityFrameworkCore.Update[10000]
An exception occurred in the database while saving changes for context type 'AnotherAP.Helpers.DataContext'.
Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while updating the entries. See the inner exception for details.
---> MySql.Data.MySqlClient.MySqlException (0x80004005): Column 'email' cannot be null
---> MySql.Data.MySqlClient.MySqlException (0x80004005): Column 'email' cannot be null
at MySqlConnector.Core.ServerSession.ReceiveReplyAsyncAwaited(ValueTask`1 task) in C:\projects\mysqlconnector\src\MySqlConnector\Core\ServerSession.cs:line 774
at MySqlConnector.Core.ResultSet.ReadResultSetHeaderAsync(IOBehavior ioBehavior) in C:\projects\mysqlconnector\src\MySqlConnector\Core\ResultSet.cs:line 49
at MySql.Data.MySqlClient.MySqlDataReader.ActivateResultSet() in C:\projects\mysqlconnector\src\MySqlConnector\MySql.Data.MySqlClient\MySqlDataReader.cs:line 130
at MySql.Data.MySqlClient.MySqlDataReader.CreateAsync(CommandListPosition commandListPosition, ICommandPayloadCreator payloadCreator, IDictionary`2 cachedProcedures, IMySqlCommand command, CommandBehavior behavior, IOBehavior ioBehavior, CancellationToken cancellationToken) in C:\projects\mysqlconnector\src\MySqlConnector\MySql.Data.MySqlClient\MySqlDataReader.cs:line 391
at MySqlConnector.Core.CommandExecutor.ExecuteReaderAsync(IReadOnlyList`1 commands, ICommandPayloadCreator payloadCreator, CommandBehavior behavior, IOBehavior ioBehavior, CancellationToken cancellationToken) in C:\projects\mysqlconnector\src\MySqlConnector\Core\CommandExecutor.cs:line 62
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(DbContext _, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Pomelo.EntityFrameworkCore.MySql.Storage.Internal.MySqlExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while updating the entries. See the inner exception for details.
---> MySql.Data.MySqlClient.MySqlException (0x80004005): Column 'email' cannot be null
---> MySql.Data.MySqlClient.MySqlException (0x80004005): Column 'email' cannot be null
at MySqlConnector.Core.ServerSession.ReceiveReplyAsyncAwaited(ValueTask`1 task) in C:\projects\mysqlconnector\src\MySqlConnector\Core\ServerSession.cs:line 774
at MySqlConnector.Core.ResultSet.ReadResultSetHeaderAsync(IOBehavior ioBehavior) in C:\projects\mysqlconnector\src\MySqlConnector\Core\ResultSet.cs:line 49
at MySql.Data.MySqlClient.MySqlDataReader.ActivateResultSet() in C:\projects\mysqlconnector\src\MySqlConnector\MySql.Data.MySqlClient\MySqlDataReader.cs:line 130
at MySql.Data.MySqlClient.MySqlDataReader.CreateAsync(CommandListPosition commandListPosition, ICommandPayloadCreator payloadCreator, IDictionary`2 cachedProcedures, IMySqlCommand command, CommandBehavior behavior, IOBehavior ioBehavior, CancellationToken cancellationToken) in C:\projects\mysqlconnector\src\MySqlConnector\MySql.Data.MySqlClient\MySqlDataReader.cs:line 391
at MySqlConnector.Core.CommandExecutor.ExecuteReaderAsync(IReadOnlyList`1 commands, ICommandPayloadCreator payloadCreator, CommandBehavior behavior, IOBehavior ioBehavior, CancellationToken cancellationToken) in C:\projects\mysqlconnector\src\MySqlConnector\Core\CommandExecutor.cs:line 62
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(DbContext _, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Pomelo.EntityFrameworkCore.MySql.Storage.Internal.MySqlExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
An unhandled exception has occurred while executing the request.
Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while updating the entries. See the inner exception for details.
---> MySql.Data.MySqlClient.MySqlException (0x80004005): Column 'email' cannot be null
---> MySql.Data.MySqlClient.MySqlException (0x80004005): Column 'email' cannot be null
at MySqlConnector.Core.ServerSession.ReceiveReplyAsyncAwaited(ValueTask`1 task) in C:\projects\mysqlconnector\src\MySqlConnector\Core\ServerSession.cs:line 774
at MySqlConnector.Core.ResultSet.ReadResultSetHeaderAsync(IOBehavior ioBehavior) in C:\projects\mysqlconnector\src\MySqlConnector\Core\ResultSet.cs:line 49
at MySql.Data.MySqlClient.MySqlDataReader.ActivateResultSet() in C:\projects\mysqlconnector\src\MySqlConnector\MySql.Data.MySqlClient\MySqlDataReader.cs:line 130
at MySql.Data.MySqlClient.MySqlDataReader.CreateAsync(CommandListPosition commandListPosition, ICommandPayloadCreator payloadCreator, IDictionary`2 cachedProcedures, IMySqlCommand command, CommandBehavior behavior, IOBehavior ioBehavior, CancellationToken cancellationToken) in C:\projects\mysqlconnector\src\MySqlConnector\MySql.Data.MySqlClient\MySqlDataReader.cs:line 391
at MySqlConnector.Core.CommandExecutor.ExecuteReaderAsync(IReadOnlyList`1 commands, ICommandPayloadCreator payloadCreator, CommandBehavior behavior, IOBehavior ioBehavior, CancellationToken cancellationToken) in C:\projects\mysqlconnector\src\MySqlConnector\Core\CommandExecutor.cs:line 62
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(DbContext _, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Pomelo.EntityFrameworkCore.MySql.Storage.Internal.MySqlExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at AnotherAP.Helpers.UserService`1.SaveAsync(T entity) in /Users/Chsyn/Projects/copyofAAP/AnotherAP/Helpers/UserService.cs:line 35
at AnotherAP.Controllers.RegisterController.PostRegister(Register register) in /Users/Chsyn/Projects/copyofAAP/AnotherAP/Controllers/RegisterController.cs:line 110
at lambda_method(Closure , Object )
at Microsoft.Extensions.Internal.ObjectMethodExecutorAwaitable.Awaiter.GetResult()
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.AwaitableObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
This is how my Create() method looks now in register.service.ts:
baseurl = 'https://localhost:5001';
constructor(private http: HttpClient) { }
Create(user): Observable<Register> {
const httpOptions = { headers: new HttpHeaders(
{ 'Content-Type': 'application/json',
'Accept': 'application/json'
})
};
return this.http.post<Register>(this.baseurl + '/register/Add' , JSON.stringify(user),
httpOptions).pipe(retry(1), catchError(this.errorHandler));
}
Could you try modifying httpOptions as below, please post your observations after trying this:
const httpOptions = { headers: new HttpHeaders(
{ 'Content-Type': 'application/json, application/x-www-form-urlencoded',
{ 'Accept': 'application/json, text/plain, */*',
/*'Access-Control-Allow-Headers': 'Authorization',
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS'*/
})
};
return this.http.post<Register>(this.baseurl, JSON.stringify(user),
httpOptions).pipe(retry(1), catchError(this.errorHandler));
}
I want to capture the error from entity framework.
So i have the below code
return await _context.SaveChangesAsync(cancellationToken);
if something goes wrong in the above code i want it to be captured as a warning in database, but as of now it is automatically saving in the database as error which has to be warning actually.
below is the error that i get
An exception occurred in the database while saving changes for context
type 'ValuationsReporting.Models.ValuationsReportingContext'.
System.InvalidOperationException: The property 'TemplateTypeId' on
entity type 'ValuationFundTemplate' has a temporary value. Either set
a permanent value explicitly or ensure that the database is configured
to generate values for this property. at
Microsoft.EntityFrameworkCore.Update.Internal.CommandBatchPreparer.Validate(ModificationCommand
modificationCommand) at
Microsoft.EntityFrameworkCore.Update.Internal.CommandBatchPreparer.BatchCommands(IReadOnlyList1
entries)+MoveNext() at
Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(DbContext
_, ValueTuple2 parameters, CancellationToken cancellationToken) at
Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.ExecuteImplementationAsync[TState,TResult](Func4
operation, Func4 verifySucceeded, TState state, CancellationToken
cancellationToken) at
Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.ExecuteImplementationAsync[TState,TResult](Func4
operation, Func4 verifySucceeded, TState state, CancellationToken
cancellationToken) at
Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IReadOnlyList`1
entriesToSave, CancellationToken cancellationToken) at
Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(Boolean
acceptAllChangesOnSuccess, CancellationToken cancellationToken) at
Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean
acceptAllChangesOnSuccess, CancellationToken cancellationToken)
System.InvalidOperationException
Microsoft.EntityFrameworkCore.Update
I tried using try catch but as soon as it goes to that line the error is logged in database.
Actual code :
try
{
foreach (var template in snapshotDto.SnapshopFundTemplateDtos)
{
if (template.FundId != null)
{
foreach (var fundId in template.FundId)
{
var tempTemplate = allFundTemplates.Where(x => x.ValuationId == valuation.Id && x.FundId == fundId && x.TemplateTypeId == template.TemplateTypeId).FirstOrDefault();
//var tempTemplate = await _valuationFundTemplateRepository.GetOne(valuation.Id, fundId, template.TemplateTypeId, true, cancellationToken);
if (tempTemplate == null)
{
tempTemplate = new ValuationFundTemplate();
tempTemplate.CreatedBy = _userRepository.claimsPrincipal.Identity.Name;
tempTemplate.CreatedOn = DateTime.Now.ToUniversalTime();
isTemplateUpdate = false;
}
//tempTemplate.IsDeleted = false;
//if (template.IsDeleted)
//{
// _valuationFundTemplateRepository.Delete(tempTemplate);
//}
//else
//{
//tempTemplate.IsDeleted = template.IsDeleted;
tempTemplate.IsDeleted = false;
tempTemplate.IsDefaultFundTemplate = template.IsDefault;
tempTemplate.FundId = fundId;
tempTemplate.ValuationId = valuation.Id;
tempTemplate.TemplateTypeId = 0;
tempTemplate.TemplateId = template.TemplateId;
tempTemplate.ModifiedBy = _userRepository.claimsPrincipal.Identity.Name;
tempTemplate.ModifiedOn = DateTime.Now.ToUniversalTime();
tempTemplates.Add(tempTemplate);
if (isTemplateUpdate)
{
_valuationFundTemplateRepository.Update(tempTemplate);
}
else
{
await _valuationFundTemplateRepository.Insert(tempTemplate, cancellationToken);
}
// }
await _valuationFundTemplateRepository.SaveAsync(cancellationToken);//here is where the error occurs which i dont want to capture in database.
if (!isTemplateUpdate)
valuation.ValuationFundTemplate.Add(tempTemplate);
}
}
}
}catch(Exception e)
{
var z = e.Message;
}
public virtual async Task<int> SaveAsync(CancellationToken cancellationToken = default(CancellationToken))
{
return await _context.SaveChangesAsync(cancellationToken);
}
Agreed with the #PrashantPimpale you can simply use try catch.
But for the advanced approach, I would suggest you can use a Global Error Handling Middleware.
Through which you can capture any error occurred in the whole dotnet API/Application.
Just and Elaboration below:
// Extension method used to add the middleware to the HTTP request pipeline.
public static class ErrorHandlingMiddlewareExtensions
{
public static IApplicationBuilder UseErrorHandlingMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<ErrorHandlingMiddleware>();
}
}
Then add app.UseErrorHandlingMiddleware(); in the Startup's Configure() method.
You have to first create a ErrorHandlingMiddleware class.
public class ErrorHandlingMiddleware
{
private readonly RequestDelegate _next;
public ErrorHandlingMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext httpContext)
{
try
{
await _next(httpContext);
}
catch (Exception ex)
{
await HandleExceptionAsync(httpContext, ex);
}
}
private static async Task HandleExceptionAsync(HttpContext context, Exception exception)
{
// Implement how you want to handle the error.
}
}
Following on from my comment on the other answer - I have found a solution to this.
There are two things not immediately clear here, so to clarify:
There are legitimate reasons for wanting to suppress some DB errors and treat them as warnings (for instance) e.g. custom triggers checking data integrity
This is NOTHING to do with capturing an exception coming from EF Core, EF Core is DIRECTLY emitting error log lines for DbUpdateExceptions AS WELL AS throwing that exception to be caught by the application
So the solution here is to configure EF Core to change its behaviour and log failures to save changes as warnings instead of errors (could suppress completely - but I'm playing safe). I haven't found actual documentation on this, but with some experimentation have found configuring your context like this works correctly:
protected override void OnConfiguring(DbContextOptionsBuilder builder)
{
base.OnConfiguring(builder);
builder
.ConfigureWarnings(x => x
.Log(
(CoreEventId.SaveChangesFailed, LogLevel.Warning)
)
);
}
Functionality:
Fetch and display relevant answer from QnAMaker
This response must be followed by an adaptive card with checkboxes
Based on the values selected, invoke a web service to provide the user with required file links.
Display a feedback message 'Did this help?'
Direct the conversation flow based on user response.
Problem Statement: For the step 2 mentioned above, the button click is being handled at the bot.cs file and redirected to a new Dialog.
Everything works fine until displaying the feedback message(which is again invoked from a new Dialog). However, after this text prompt the
next step is not called and exits with an error: The given key 'dialogs' was not present in the dictionary.
Why does it show that error without going to the next step?
bot.cs
public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
{
if (turnContext.Activity.Type == ActivityTypes.Message)
{
if (turnContext.Activity.Text != null)
{
if (!dc.Context.Responded)
{
// examine results from active dialog
switch (dialogResult.Status)
{
case DialogTurnStatus.Empty:
switch (topIntent)
{
case ...
}
break;
case ...
}
}
}
else if (string.IsNullOrEmpty(turnContext.Activity.Text))
{
await HandleSubmitActionAsync(turnContext, userProfile);
}
}
}
private async Task HandleSubmitActionAsync(ITurnContext turnContext, UserProfile userProfile)
{
if (value.Type == "GetCredentials")
{
userProfile.credentialsCard = true;
}
await dc.BeginDialogAsync(nameof(HandleButtonDialog));
}
HandleButtonDialog:
public HandleButtonDialog(BotServices _services, UserProfile _userProfile) : base(Name)
{
botServices = _services ?? throw new ArgumentNullException(nameof(_services));
userProfile = _userProfile;
var waterfallSteps = new WaterfallStep[]
{
GetFeedbackStepAsync,
FeedbackStepAsync,
FeedbackResponseStepAsync,
};
AddDialog(new WaterfallDialog(HBFeedbackDialog));
AddDialog(new TextPrompt("userFeed"));
}
public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
{
if...
else if(userProfile.credentialsCard == true)
{
await dc.BeginDialogAsync(HandleCredentialsFeedbackDialog.Name);
}
}
HandleCredentialsFeedbackDialog:
public class HandleCredentialsFeedbackDialog : ComponentDialog
{
public HandleCredentialsFeedbackDialog(BotServices services, UserProfile _userProfile,string dialogId = null) : base(Name)
{
botServices = services ?? throw new ArgumentNullException(nameof(services));
userProfile = _userProfile;
// This array defines how the Waterfall will execute.
var waterfallSteps = new WaterfallStep[]
{
CredsValidate,
GetFeedbackStepAsync,
FeedbackStepAsync,
FeedbackResponseStepAsync,
};
AddDialog(new TextPrompt("userFeed"));
AddDialog(new WaterfallDialog(HBFeedbackDialog, waterfallSteps));
InitialDialogId = HBFeedbackDialog;
}
public async Task<DialogTurnResult> CredsValidate(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
VALIDATE THE CHECKBOX SELECTED VALUES
....
//Invoke Web Service
var qnaReuslt = await MakeBatchRequestCreds(stepContext.Context, finalSearchList.ToArray());
return await stepContext.PromptAsync("userFeed", new PromptOptions
{
Prompt = stepContext.Context.Activity.CreateReply("Did this help?")
});
}
}
Error Stack Trace:
at System.Collections.Generic.Dictionary`2.get_Item(TKey key)
at Microsoft.Bot.Builder.Dialogs.ComponentDialog.RepromptDialogAsync(ITurnContext turnContext, DialogInstance instance, CancellationToken cancellationToken) in d:\a\1\s\libraries\Microsoft.Bot.Builder.Dialogs\ComponentDialog.cs:line 112
at Microsoft.Bot.Builder.Dialogs.ComponentDialog.ResumeDialogAsync(DialogContext outerDc, DialogReason reason, Object result, CancellationToken cancellationToken) in d:\a\1\s\libraries\Microsoft.Bot.Builder.Dialogs\ComponentDialog.cs:line 106
at Microsoft.Bot.Builder.Dialogs.DialogContext.EndDialogAsync(Object result, CancellationToken cancellationToken) in d:\a\1\s\libraries\Microsoft.Bot.Builder.Dialogs\DialogContext.cs:line 196
at AESAiLean.Dialogs.HandleButtonDialog.BeginDialogAsync(DialogContext dc, Object options, CancellationToken cancellationToken) in C:\Users\...\Dialogs\HandleButtonDialog.cs:line 199
at Microsoft.Bot.Builder.Dialogs.DialogContext.BeginDialogAsync(String dialogId, Object options, CancellationToken cancellationToken) in d:\a\1\s\libraries\Microsoft.Bot.Builder.Dialogs\DialogContext.cs:line 113
at AESAiLean.AESAiLeanBot.HandleSubmitActionAsync(ITurnContext turnContext, UserProfile userProfile) in C:\Users\...\Bots\AESAiLeanBot.cs:line 361