I built a very basic Scheduler implementation for testing purposes and connected it to a SQL database with EF Core and an OData V4 controller. I can create and read both single and recurring appointments, but I can only update or delete single appointments. When I try to update or delete a recurring appointment, I get the following error in the browser dev tools and no request is made to the API:
System.Net.Http.HttpRequestException: Unable to write content to request stream; content would exceed Content-Length.
---> System.Net.Http.HttpRequestException
--- End of inner exception stack trace ---
at Syncfusion.Blazor.Data.HttpHandler.SendRequest(HttpRequestMessage data)
at Syncfusion.Blazor.Data.ODataAdaptor.PerformDataOperation[T](Object queries)
at Syncfusion.Blazor.DataManager.SaveChanges[T](Object changed, Object added, Object deleted, String keyField, Nullable`1 dropIndex, String tableName, Query query, Object Original)
at Syncfusion.Blazor.Schedule.Internal.CrudModule`1.ProcessEntireSeries(List`1 eventsData, ActionType actionType)
at Syncfusion.Blazor.Schedule.Internal.CrudModule`1.DeleteEvents(List`1 deleteEvents, Nullable`1 action)
at Syncfusion.Blazor.Schedule.Internal.CrudModule`1.DeleteEvents(List`1 deleteEvents, Nullable`1 action)
at Syncfusion.Blazor.Schedule.Internal.AlertWindow`1.OnDeleteSeriesClick(MouseEventArgs args)
at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task)
at Syncfusion.Blazor.Internal.SfBaseUtils.InvokeEvent[T](Object eventFn, T eventArgs)
at Syncfusion.Blazor.Buttons.SfButton.OnClickHandler(MouseEventArgs args)
at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task)
at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle, ComponentState owningComponentState)
Here is the component with the Scheduler:
@using Syncfusion.Blazor.Data;
@using Syncfusion.Blazor.Schedule
<SfSchedule
TValue=TicketCalendar.Shared.Models.EF.Appointment
@bind-SelectedDate="@currentDate">
<ScheduleEventSettings
TValue="TicketCalendar.Shared.Models.EF.Appointment"
Query="@QueryData">
<SfDataManager
Url="https://localhost:7025/odata"
Adaptor="Adaptors.ODataV4Adaptor">
</SfDataManager>
</ScheduleEventSettings>
<ScheduleViews>
<ScheduleView Option="View.Day"></ScheduleView>
<ScheduleView Option="View.Week"></ScheduleView>
<ScheduleView Option="View.WorkWeek"></ScheduleView>
<ScheduleView Option="View.Month"></ScheduleView>
<ScheduleView Option="View.Agenda"></ScheduleView>
</ScheduleViews>
</SfSchedule>
@code {
DateTime currentDate = DateTime.Today;
public Query QueryData = new Query().From("Appointments");
}
And here is the OData controller:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.OData.Deltas;
using Microsoft.AspNetCore.OData.Query;
using Microsoft.AspNetCore.OData.Routing.Controllers;
using TicketCalendar.Shared.Models.EF;
namespace TicketCalendar.Api.Controllers
{
public class AppointmentsController : ODataController, IDisposable
{
readonly AppDbContext _db;
public AppointmentsController(AppDbContext db)
{
_db = db;
}
[EnableQuery]
public ActionResult Get()
{
return Ok(_db.Appointments);
}
[EnableQuery]
public ActionResult Get([FromRoute]int key)
{
var item = _db.Appointments.SingleOrDefault(appt => appt.Id.Equals(key));
if (item == null)
return NotFound();
return Ok(item);
}
public ActionResult Post([FromBody]Appointment eventData)
{
try
{
Appointment insertData = new();
insertData.Id = (_db.Appointments.ToList().Count > 0 ? _db.Appointments.ToList().Max(p => p.Id) : 1) + 1;
insertData.Subject = eventData.Subject;
insertData.Location = eventData.Location;
insertData.StartTime = Convert.ToDateTime(eventData.StartTime);
insertData.EndTime = Convert.ToDateTime(eventData.EndTime);
insertData.StartTimezone = eventData.StartTimezone;
insertData.EndTimezone = eventData.EndTimezone;
insertData.Description = eventData.Description;
insertData.IsAllDay = eventData.IsAllDay;
insertData.IsBlock = eventData.IsBlock;
insertData.IsReadOnly = eventData.IsReadOnly;
insertData.FollowingID = eventData.FollowingID;
insertData.RecurrenceID = eventData.RecurrenceID;
insertData.RecurrenceRule = eventData.RecurrenceRule;
insertData.RecurrenceException = eventData.RecurrenceException;
_db.Appointments.Add(insertData);
_db.SaveChanges();
return Created(insertData);
}
catch
{
return BadRequest();
}
}
public ActionResult Put([FromRoute]int key, [FromBody]Appointment eventData)
{
var appt = _db.Appointments.SingleOrDefault(a => a.Id == key);
if (appt == null)
return NotFound();
appt.Subject = eventData.Subject;
appt.Location = eventData.Location;
appt.StartTime = Convert.ToDateTime(eventData.StartTime);
appt.EndTime = Convert.ToDateTime(eventData.EndTime);
appt.StartTimezone = eventData.StartTimezone;
appt.EndTimezone = eventData.EndTimezone;
appt.Description = eventData.Description;
appt.IsAllDay = eventData.IsAllDay;
appt.IsBlock = eventData.IsBlock;
appt.IsReadOnly = eventData.IsReadOnly;
appt.FollowingID = eventData.FollowingID;
appt.RecurrenceID = eventData.RecurrenceID;
appt.RecurrenceRule = eventData.RecurrenceRule;
appt.RecurrenceException = eventData.RecurrenceException;
_db.SaveChanges();
return Updated(appt);
}
public ActionResult Patch([FromRoute]int key, [FromBody]Delta<Appointment> delta)
{
var appt = _db.Appointments.SingleOrDefault(a => a.Id == key);
if (appt == null)
return NotFound();
delta.Patch(appt);
_db.SaveChanges();
return Updated(appt);
}
public ActionResult Delete([FromRoute]int key)
{
var appt = _db.Appointments.SingleOrDefault(a => a.Id == key);
if (appt != null)
{
_db.Appointments.Remove(appt);
_db.SaveChanges();
}
return NoContent();
}
public void Dispose()
{
_db.Dispose();
GC.SuppressFinalize(this);
}
}
}
Here is the appointment model:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;
namespace TicketCalendar.Shared.Models.EF;
public partial class Appointment
{
[Key]
public int Id { get; set; }
[StringLength(100)]
[Unicode(false)]
public string Subject { get; set; } = null!;
[StringLength(200)]
[Unicode(false)]
public string? Location { get; set; }
[Column(TypeName = "datetime")]
public DateTime? StartTime { get; set; }
[Column(TypeName = "datetime")]
public DateTime? EndTime { get; set; }
[StringLength(50)]
public string? StartTimezone { get; set; }
[StringLength(50)]
public string? EndTimezone { get; set; }
[StringLength(2000)]
[Unicode(false)]
public string? Description { get; set; }
public bool? IsAllDay { get; set; }
public bool? IsBlock { get; set; }
public bool? IsReadOnly { get; set; }
public int? FollowingID { get; set; }
[StringLength(1000)]
[Unicode(false)]
public string? RecurrenceRule { get; set; }
public int? RecurrenceID { get; set; }
[StringLength(1000)]
[Unicode(false)]
public string? RecurrenceException { get; set; }
}
And the DB context class:
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
namespace TicketCalendar.Shared.Models.EF;
public partial class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options)
: base(options)
{
}
public virtual DbSet<Appointment> Appointments { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Appointment>(entity =>
{
entity.Property(e => e.Id).ValueGeneratedNever();
});
OnModelCreatingPartial(modelBuilder);
}
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}
Hi Chris,
We have checked your reported problem at our end. We suspect that maybe you have missed adding the following changes at the server project end. We prepared a working sample for your reference. Try the shared sample and let us know if you need any further assistance on this.
[Program.cs]
var builder = WebApplication.CreateBuilder(args);
static IEdmModel GetEdmModel() { ODataConventionModelBuilder builder = new(); builder.EntitySet<Event>("Events"); return builder.GetEdmModel(); }
// Add services to the container.
// OData batch handling var batchHandler = new DefaultODataBatchHandler(); builder.Services.AddControllers().AddOData(opt => opt.AddRouteComponents("api", GetEdmModel(), batchHandler).Filter().Select().OrderBy().Expand().SetMaxTop(null).Count());
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen();
builder.Services.AddDbContext<EventsContext>(options => options.UseInMemoryDatabase("EventDb"));
var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); }
// OData batch handling app.UseODataBatching(); app.UseHttpsRedirection(); // Routing app.UseRouting(); app.UseAuthorization();
app.MapControllers();
app.Run(); |
Regards,
Ravikumar Venkatesan
Thank you for your reply. I have found that I can replicate the error in your attached sample project, syncfusion-blazor-carousel, by changing the Target Framework to net7.0.
Chris,
We regret for the delay.
While validating the stated issue, we are facing some complexity at the source level and need additional time to validate this further. So, we will update you further details on 10th January 2023. Appreciate your patience until then.
Hi Chris,
We apologize for the inconvenience you have experienced after upgrading to the .Net7 version. We can reproduce the issue you reported and we have identified that the issue is likely caused by changes in the framework. We have therefore decided to raise an issue on GitHub to address this problem and we will keep you updated on the progress.
As a temporary solution, we suggest that you use the .Net6 version of the Blazor project until this issue is resolved. We apologize for any inconvenience this may cause and we appreciate your patience as we work to resolve this issue. Please let us know if there is anything else we can do to assist you.
Regards,
Ravikumar Venkatesan
Chris,
We are glad to inform you that the issue has been resolved at our end.
To resolve the issue we recommend you upgrade to our latest version 20.4.0.49. If you face any difficulties during the upgrade process, please do not hesitate to reach out to us.