Issue with Telerik Scheduler using Chrome - c#-3.0

I have implemented code in environment of asp.net C# to drag and drop from Telerik treeview into Telerik scheduler to create appointment.
I got the problem into only Chrome sometimes when going to schedule any appointment by drag and drop into Telerik scheduler from Telerik treeview.
Error description is as below:
"1176.666697837689 is not a valid value for Int32." Every time decimal value is changing.
Error ExceptionStackTrace is as below:
at System.ComponentModel.BaseNumberConverter.ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, Object value)
at System.ComponentModel.TypeConverter.ConvertFromInvariantString(String text)
at System.Web.Script.Serialization.ObjectConverter.ConvertObjectToTypeInternal(Object o, Type type, JavaScriptSerializer serializer, Boolean throwOnError, Object& convertedObject)
at System.Web.Script.Serialization.ObjectConverter.ConvertObjectToTypeMain(Object o, Type type, JavaScriptSerializer serializer, Boolean throwOnError, Object& convertedObject)
at System.Web.Script.Serialization.ObjectConverter.AssignToPropertyOrField(Object propertyValue, Object o, String memberName, JavaScriptSerializer serializer, Boolean throwOnError)
at System.Web.Script.Serialization.ObjectConverter.ConvertDictionaryToObject(IDictionary`2 dictionary, Type type, JavaScriptSerializer serializer, Boolean throwOnError, Object& convertedObject)
at System.Web.Script.Serialization.ObjectConverter.ConvertObjectToTypeInternal(Object o, Type type, JavaScriptSerializer serializer, Boolean throwOnError, Object& convertedObject)
at System.Web.Script.Serialization.ObjectConverter.ConvertObjectToTypeMain(Object o, Type type, JavaScriptSerializer serializer, Boolean throwOnError, Object& convertedObject)
at System.Web.Script.Serialization.JavaScriptSerializer.Deserialize(JavaScriptSerializer serializer, String input, Type type, Int32 depthLimit)
at System.Web.Script.Serialization.JavaScriptSerializer.Deserialize[T](String input)
at Telerik.Web.UI.RadScheduler.LoadPostData(String postDataKey, NameValueCollection postCollection)
at Telerik.Web.UI.RadDataBoundControl.System.Web.UI.IPostBackDataHandler.LoadPostData(String postDataKey, NameValueCollection postCollection)
at System.Web.UI.Page.ProcessPostData(NameValueCollection postData, Boolean fBeforeLoad)
at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
I have used below code to to drag and drop from Telerik treeview to Telerik Scheduler :
<telerik:RadScriptBlock ID="RadScriptBlock1" runat="server">
<script type="text/javascript">
//<![CDATA[
//Shows whether an Appointment is inserted directry, or the
//the Advanced Insert Form is opened when TreeView node is dropped on the Scheduler.
var directlyInsertAppointment = true;
var selectedAppointment = null;
function nodeDropping(sender, eventArgs) {
var htmlElement = eventArgs.get_htmlElement();
var scheduler = $find('<%= RadScheduler1.ClientID %>');
if (isPartOfSchedulerAppointmentArea(htmlElement)) {
//Gets the TimeSlot where an Appointment is dropped.
var timeSlot = scheduler.get_activeModel().getTimeSlotFromDomElement(htmlElement);
var startTime = timeSlot.get_startTime();
var startTimes = startTime.toDateString() + " " + startTime.toTimeString();
document.getElementById('<%= hdnScheduledStartDateTime.ClientID %>').value = startTimes;
//Gets all the data needed for the an Appointment, from the TreeView node.
var node = eventArgs.get_sourceNode();
var text = node.get_text();
document.getElementById('<%= hdnSessionSubject.ClientID%>').value = text;
var nodeVal = node.get_value();
document.getElementById('<%= hdnPTSessionsClientManagementId.ClientID %>').value = nodeVal;
var attributes = node.get_attributes();
var PTSessionMgmtID = attributes.getAttribute("PTSessionsManagementId");
document.getElementById('<%= hdnPTSessionsManagementId.ClientID %>').value = PTSessionMgmtID;
var SessionTypeId = attributes.getAttribute("SessionTypeId");
document.getElementById('<%= hdnSessionTypeId.ClientID %>').value = SessionTypeId;
var duration = attributes.getAttribute("Duration");
var endTime = new Date(startTime);
endTime.setMinutes(parseInt(endTime.getMinutes()) + parseInt(duration));
var endTimes = endTime.toDateString() + " " + endTime.toTimeString();
document.getElementById('<%= hdnScheduledEndDateTime.ClientID %>').value = endTimes;
var parentValue = node.get_parent().get_value();
var category = scheduler.get_resources().getResourceByTypeAndKey("Category", parentValue);
//New appointment is created. The start/end time, subject and category are set.
var newAppointment = new Telerik.Web.UI.SchedulerAppointment();
newAppointment.set_start(startTime);
newAppointment.set_end(endTime);
newAppointment.set_subject(text);
if (category != null) {
newAppointment.get_resources().add(category);
}
//Checks for the user's choice of the method for inserting Appointments.
if (directlyInsertAppointment) {
scheduler.insertAppointment(newAppointment);
} else {
//If Advanced Form is opened, the information from the TreeVew node is stored in a hidden input.
var appointmentInfo = { subject: text, duration: duration, category: category };
var appointmentInfoSerialized = Sys.Serialization.JavaScriptSerializer.serialize(appointmentInfo);
$get("<%=HiddenInputAppointmentInfo.ClientID%>").value = appointmentInfoSerialized;
scheduler.showInsertFormAt(timeSlot);
}
}
else {
//The node was dropped elsewhere on the document.
eventArgs.set_cancel(true);
}
}
</script>
This functionality is working properly on local server but somehow it's not working on client server, sometimes in Chrome browser.

Apparently it's fixed in newer versions of Telerik, but caused by Google Chrome now sending fractional pixel values for scroll positions:
Some workarounds are listed here: https://www.telerik.com/forums/system-formatexception-78e82e51af27#KkKRUtkEq0ST4A09XY_eZQ

Related

Does EF Core Have a Query Que?

I am new to EF Core and am trying to figure out why I keep having to increase my SQl timeout setting to make a specific query work. In the process I developed a theory. What if EF has a que of pending requests and when there are too many it just stops working instead of removing older requests from the que. That might explain why increasing timeout time is the only way to keep my browser from showing "err connection closed" when I load pages using a specific query.
I tried posting the query on the Microsoft Q and A website with my problem a couple days ago (https://learn.microsoft.com/en-us/answers/questions/601858/aspnet-core-app-only-works-for-few-minutes-after-r.html), but as usual Microsoft has not responded with an explanation that specifically explains why their product does not work and how to fix it. The best responses I've gotten are vague suggestions that don't really explain what to do.
For instance, one guy suggest not using ToArray() but doesn't say how the same functionality can be obtained without it. Another guy suggests researching connection resiliency but doesn't say how doing that might solve my problem.
So far I have managed to keep the app running longer without this problem occurring by using LazyCache to cache results of the problem query, but after a couple days the app is having the same problem again. Why is it that Microsoft is quick to tell people not to do something, but never tells people what to do instead?
UPDATE: Since Microsoft requires people to sign into their account to access the above link and nobody here want to sign in here is part of what is posted there. It is an error message from running my app locally
An unhandled exception occurred while processing the request.
Win32Exception: The wait operation timed out.
Unknown location
SqlException: Execution Timeout Expired. The timeout period elapsed prior to completion of the operation or the server is not responding.
Microsoft.Data.SqlClient.SqlCommand+<>c.<ExecuteDbDataReaderAsync>b__169_0(Task<SqlDataReader> result)
Stack Query Cookies Headers Routing
Win32Exception: The wait operation timed out.
Show raw exception details
SqlException: Execution Timeout Expired. The timeout period elapsed prior to completion of the operation or the server is not responding.
Microsoft.Data.SqlClient.SqlCommand+<>c.<ExecuteDbDataReaderAsync>b_169_0(Task<SqlDataReader> result)
System.Threading.Tasks.ContinuationResultTaskFromResultTask<TAntecedentResult, TResult>.InnerInvoke()
System.Threading.Tasks.Task+<>c.<.cctor>b277_0(object obj)
System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, object state)
System.Threading.Tasks.Task.ExecuteWithThreadLocal(ref Task currentTaskSlot, Thread threadPoolThread)
Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable<T>+AsyncEnumerator.InitializeReaderAsync(DbContext , bool result, CancellationToken cancellationToken)
Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.ExecuteImplementationAsync<TState, TResult>(Func<DbContext, TState, CancellationToken, Task<TResult>> operation, Func<DbContext, TState, CancellationToken, Task<ExecutionResult<TResult>>> verifySucceeded, TState state, CancellationToken cancellationToken)
Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.ExecuteImplementationAsync<TState, TResult>(Func<DbContext, TState, CancellationToken, Task<TResult>> operation, Func<DbContext, TState, CancellationToken, Task<ExecutionResult<TResult>>> verifySucceeded, TState state, CancellationToken cancellationToken)
Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable<T>+AsyncEnumerator.MoveNextAsync()
Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync<TSource>(IQueryable<TSource> source, CancellationToken cancellationToken)
Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync<TSource>(IQueryable<TSource> source, CancellationToken cancellationToken)
Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToArrayAsync<TSource>(IQueryable<TSource> source, CancellationToken cancellationToken)
PostAlmostAnything.SiteServices.PostsService.GetPosts() in PostsService.cs
}
public async Task<Posts[]> GetPosts()
{
IAppCache cache = new CachingService(CachingService.DefaultCacheProvider) { DefaultCachePolicy = new CacheDefaults { DefaultCacheDurationSeconds = GlobalStatic.SITEPOSTSCACHEDURATION() } };
string cacheKey = $"GetPosts";
var cacheobject = await (from post in _context.Posts
where post.Active == (bool?)true && post.Adminban == (bool?)false && post.Site == (int?)GlobalStatic.SITENUMBER()
select post into pts
select new Posts
{
Postid = pts.Postid,
Title = pts.Title,
PostAlmostAnything.SiteServices.PostsService.GetPaginatedResult(int currentPage, int pageSize) in PostsService.cs
Sc2url = linkgenerator.subcategory2link($"{pts.CategoryNavigation.Categoryurl}", $"{pts.SubcategoryNavigation.Subcategoryurl}", $"{pts.Subcategory2Navigation.Subcategory2url}")
}
}).ToArrayAsync();
}
public async Task<List<Posts>> GetPaginatedResult(int currentPage, int pageSize)
{
return (await GetPosts()).OrderByDescending((Posts d) => d.Postid).Skip((currentPage - 1) * pageSize).Take(pageSize)
.ToList();
}
public async Task<List<Posts>> GetPaginatedResultByCategoryCity(string catslug, string waslug, string regionslug, string cityslug, int currentPage, int pageSize)
{
return (from d in await GetPosts()
PostAlmostAnything.Pages.IndexModel.OnGetAsync() in Index.cshtml.cs
{
PostService = postService;
}
public async Task<PageResult> OnGetAsync()
{
Posts = await PostService.GetPaginatedResult(CurrentPage, PageSize);
return Page();
}
}
}
Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.ExecutorFactory+GenericTaskHandlerMethod.Convert<T>(object taskAsObject)
Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.ExecutorFactory+GenericTaskHandlerMethod.Execute(object receiver, object[] arguments)
Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.InvokeHandlerMethodAsync()
Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.InvokeNextPageFilterAsync()
Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.Rethrow(PageHandlerExecutedContext context)
Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.InvokeInnerFilterAsync()
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g_Awaited|24_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.<InvokeFilterPipelineAsync>gAwaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>gLogged|17_1(ResourceInvoker invoker)
Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g_AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.MigrationsEndPointMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.Invoke(HttpContext httpContext)
Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.Invoke(HttpContext httpContext)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
UPDATE: Here is where I am now as far as trying to paginate the query. I cannot find a way to use an IQueryable and access it with an async task without getting errors for lacking GetAwaiter
public IQueryable<Posts> GetPosts(bool active)
{
var query = _context.Posts.Where(post => post.Active == active && post.Adminban == (bool?)false && post.Site == GlobalStatic.SITENUMBER());
return query;
}
public IQueryable<Posts> GetPaginatedResult(bool active, int currentPage, int pageSize)
{
//IAppCache cache = new CachingService(CachingService.DefaultCacheProvider) { DefaultCachePolicy = new CacheDefaults { DefaultCacheDurationSeconds = GlobalStatic.SITEPOSTSCACHEDURATION() } };
//string cacheKey = $"GetPosts";
var cacheobject = GetPosts(active)
.Select(pts => new Posts
{
Postid = pts.Postid,
Title = pts.Title,
Description = pts.Description,
Dateposted = pts.Dateposted,
Datemodified = pts.Datemodified,
Video = pts.Video,
Videostream = pts.Videostream,
Location = pts.Location,
Tags = pts.Tags,
Cap = pts.Cap,
Titletag = pts.Titletag,
Metatag = pts.Metatag,
Link = pts.Link,
Linkurl = pts.Linkurl,
Category = pts.Category,
Subcategory = pts.Subcategory,
Subcategory2 = pts.Subcategory2,
Worldarea = pts.Worldarea,
Region = pts.Region,
City = pts.City,
Sendemail = pts.Sendemail,
Userid = pts.Userid,
Active = pts.Active,
Adminban = pts.Adminban,
Posturl = linkgenerator.postlink($"{pts.Postid}", $"{pts.Title}"),
Comments = (from cm in pts.Comments
where cm.Active == (bool?)true && cm.Adminblock == (bool?)false
select cm into cmts
select new Comments
{
Commentid = cmts.Commentid,
Comment = cmts.Comment,
Date = cmts.Date,
Active = cmts.Active,
Adminblock = cmts.Adminblock,
Userid = cmts.Userid,
Post = cmts.Post,
Ratings = cmts.Ratings.Select((Ratings rts) => new Ratings
{
Commentnumber = rts.Commentnumber,
Rating = rts.Rating
}).ToArray(),
Images = cmts.Images.Select((Images imgs) => new Images
{
Image = imgs.Image,
Imagename = imgs.Imagename
}).ToArray(),
Likes = cmts.Likes.Select((Likes lks) => new Likes
{
Likeid = lks.Likeid,
Commentid = lks.Commentid
}).ToArray()
}).ToArray(),
Commentcount = pts.Comments.Where((Comments cm) => cm.Active == (bool?)true && cm.Adminblock == (bool?)false).Count(),
Ratings = (from r in pts.Ratings
where r.CommentnumberNavigation.Active == (bool?)true && r.CommentnumberNavigation.Adminblock == (bool?)false
select r into rtgs
select new Ratings
{
Ratingid = rtgs.Ratingid,
Rating = rtgs.Rating,
Daterated = rtgs.Daterated,
CommentnumberNavigation = new Comments
{
Commentid = rtgs.CommentnumberNavigation.Commentid
}
}).ToArray(),
Ratingcount = pts.Ratings.Where((Ratings rc) => rc.CommentnumberNavigation.Active == (bool?)true && rc.CommentnumberNavigation.Adminblock == (bool?)false).Count(),
Ratingavg = ratingavg((from rac in pts.Ratings
where rac.CommentnumberNavigation.Active == (bool?)true && rac.CommentnumberNavigation.Adminblock == (bool?)false
select rac into ra
select ra.Rating).Average()),
Images = pts.Images.Select((Images imgs) => new Images
{
Imageid = imgs.Imageid,
Imagename = imgs.Imagename,
Image = imgs.Image,
Imagetype = imgs.Imagetype,
Postid = imgs.Postid,
Comment = imgs.Comment,
Userid = imgs.Userid
}).ToArray(),
Primaryimage = computations.primaryimage((from pic in pts.Images
where pic.Imagetype == (int?)1
select pic into pi
select new Images
{
Imageid = pi.Imageid,
Image = pi.Image,
Imagename = pi.Imagename
}).DefaultIfEmpty().First()),
Likes = pts.Likes.Select((Likes lks) => new Likes
{
Likeid = lks.Likeid,
Post = lks.Post,
Commentid = lks.Commentid
}).ToArray(),
Likecount = pts.Likes.Where((Likes lc) => lc.Commentid == null).Count(),
WorldareaNavigation = new Worldarea
{
Worldarea1 = pts.WorldareaNavigation.Worldarea1,
Worldareaacronym = pts.WorldareaNavigation.Worldareaacronym,
Wurl = linkgenerator.worldarealink($"{pts.WorldareaNavigation.Worldareaacronym}")
},
RegionNavigation = new Regions
{
Regionname = pts.RegionNavigation.Regionname,
Regionacronym = pts.RegionNavigation.Regionacronym,
Rurl = linkgenerator.regionlink($"{pts.WorldareaNavigation.Worldareaacronym}", $"{pts.RegionNavigation.Regionacronym}")
},
CityNavigation = new Cities
{
City = pts.CityNavigation.City,
Cityacronym = pts.CityNavigation.Cityacronym,
Cityurl = linkgenerator.citylink($"{pts.WorldareaNavigation.Worldareaacronym}", $"{pts.RegionNavigation.Regionacronym}", $"{pts.CityNavigation.Cityacronym}")
},
CategoryNavigation = new Categories
{
Categoryname = pts.CategoryNavigation.Categoryname,
Categorylongname = pts.CategoryNavigation.Categorylongname,
Categorytitle = pts.CategoryNavigation.Categorytitle,
Categorydescription = pts.CategoryNavigation.Categorydescription,
Categorykeywords = pts.CategoryNavigation.Categorykeywords,
Categorymeta = pts.CategoryNavigation.Categorymeta,
Categoryurl = pts.CategoryNavigation.Categoryurl,
Curl = linkgenerator.categorylink($"{pts.CategoryNavigation.Categoryurl}")
},
SubcategoryNavigation = new Subcategories
{
Subcategoryname = pts.SubcategoryNavigation.Subcategoryname,
Subcategorylongname = pts.SubcategoryNavigation.Subcategorylongname,
Subcategorytitle = pts.SubcategoryNavigation.Subcategorytitle,
Subcategorydescription = pts.SubcategoryNavigation.Subcategorydescription,
Subcategorymeta = pts.SubcategoryNavigation.Subcategorymeta,
Subcategorykeywords = pts.SubcategoryNavigation.Subcategorykeywords,
Subcategoryurl = pts.SubcategoryNavigation.Subcategoryurl,
Scurl = linkgenerator.subcategorylink($"{pts.CategoryNavigation.Categoryurl}", $"{pts.SubcategoryNavigation.Subcategoryurl}")
},
Subcategory2Navigation = new Subcategory2
{
Subcategory2name = pts.Subcategory2Navigation.Subcategory2name,
Subcategory2longname = pts.Subcategory2Navigation.Subcategory2longname,
Subcategory2title = pts.Subcategory2Navigation.Subcategory2title,
Subcategory2description = pts.Subcategory2Navigation.Subcategory2description,
Subcategory2meta = pts.Subcategory2Navigation.Subcategory2meta,
Subcategory2keywords = pts.Subcategory2Navigation.Subcategory2keywords,
Subcategory2url = pts.Subcategory2Navigation.Subcategory2url,
Sc2url = linkgenerator.subcategory2link($"{pts.CategoryNavigation.Categoryurl}", $"{pts.SubcategoryNavigation.Subcategoryurl}", $"{pts.Subcategory2Navigation.Subcategory2url}")
}
}).OrderByDescending((Posts d) => d.Postid).Skip((currentPage - 1) * pageSize).Take(pageSize);
//Func<List<Posts>> actionThatWeWantToCache = () => cacheobject;
//var CachedAdapter = cache.GetOrAdd(cacheKey, actionThatWeWantToCache);
return cacheobject;
}```
Ok, here's your problem with code like this:
public async Task<Posts[]> GetPosts()
{
IAppCache cache = new CachingService(CachingService.DefaultCacheProvider) { DefaultCachePolicy = new CacheDefaults { DefaultCacheDurationSeconds = GlobalStatic.SITEPOSTSCACHEDURATION() } };
string cacheKey = $"GetPosts";
var cacheobject = await (from post in _context.Posts
where post.Active == (bool?)true && post.Adminban == (bool?)false && post.Site == (int?)GlobalStatic.SITENUMBER()
select post into pts
select new Posts
{
Postid = pts.Postid,
Title = pts.Title,
Sc2url = linkgenerator.subcategory2link($"{pts.CategoryNavigation.Categoryurl}", $"{pts.SubcategoryNavigation.Subcategoryurl}", $"{pts.Subcategory2Navigation.Subcategory2url}")
}
}).ToArrayAsync();
}
public async Task<List<Posts>> GetPaginatedResult(int currentPage, int pageSize)
{
return (await GetPosts()).OrderByDescending((Posts d) => d.Postid).Skip((currentPage - 1) * pageSize).Take(pageSize)
.ToList();
}
GetPosts is doing a ToArray which will look to materialize your ENTIRE table into entities BEFORE doing pagination.... This is also calling C# code like this linkgenerator(...) method which will trigger client-side evaluation which is a huge performance no-no since that will also materialize the related entities for all rows. You are then selecting the Post Entities into another class called Posts which is either a Post entity instance or a separate DTO/ViewModel in order to capture this link.
This is a common sin when I see developers pursuing DNRY (Do Not Repeat Yourself) to keep common logic in one place, and then employ patterns that treat everything consistently for consistency's sake.
GetPosts() is a dangerous method if it returns an array of posts as it would always return everything where the code you are calling wants to optimize for paginated results. This is very common in Generic implementations which force a one-size-fits-all on operations. Some tables will be small enough that a "GetAll" type operation is reasonable safe, however that common method against another table can halt a system for no good reason.
To satisfy DNRY, centralize the common query into a private method that can be called as needed. A public GetAll() method for Posts is probably never needed for this entity so I would remove it:
private IQueryable<Post> getPosts()
{
var query = _context.Posts
.Where(post => post.Active
&& !post.Adminban
&& post.Site == GlobalStatic.SITENUMBER());
return query;
}
This method can be called by every method that wants to query across Posts and their related details. This centralizes your common rules around active state, and tenancy. (ownership)
Now to your GetPaginatedResult method. Here you're going to want to ensure you are selecting your desired data. I would recommend declaring a ViewModel for the post data given you want to have some computed values.
[Serializable]
public class PostViewModel
{
public int PostId { get; set; }
public string Title { get; set; }
public string CategoryUrl { get; set; }
public string SubcategoryUrl { get; set; }
public string Subcategory2Url { get; set; }
public string Sc2Url
{
get { return linkgenerator.subcategory2link(CategoryUrl, SubcategoryUrl, Subcategory2url); }
}
}
Within Linq expressions we want to select all of the raw data from the entity and associated other entities. Where we want to compose/calculate values, we can expose getters in the view model that do this calculation as needed using the raw data.
And for the GetPaginatedResult method:
public async Task<List<Posts>> GetPaginatedResult(int currentPage, int pageSize)
{
var posts = await getPosts()
.Select(x => new PostViewModel
{
PostId = x.PostId,
Title = x.Title,
CategoryUrl = x.CategoryNavigation.Categoryurl,
SubcategoryUrl = x.SubcategoryNavigation.Subcategoryurl,
SubcategoryUrl = x.Subcategory2Navigation.Subcategory2url
}).Skip((currentPage -1) * pageSize)
.Take(pageSize)
.ToListAsync();
}
Note that the Select only selects the raw values from the Post and associated entities. It doesn't attempt to calculate the full link. The view model will take care of that when the property is accessed, such as when it is referenced to compose a view or serialized. You can perform simple computed fields in the Linq expression, but only basic stuff like appending strings together with "+" and some simple functions that EF can translate. Even String.Format (including $"{value}") is off the cards inside a Linq expression fed to EF. It cannot translate that to SQL so it would fall on client-side evaluation and you want to avoid that at all costs. By default with EF Core 2, client-side evaluation was on by default, with EF Core 3.1 onward it is off by default but some teams turn it on. I highly recommend leaving it off as it's a bigger landmine than lazy loading.
That should eliminate your performance issues. This generates a compact SQL statement taking into account the desired pagination and serializes just those results into a view model to return to the view. The core business rules around ownership can be cetralized, and by exposing IQueryable it is left to the consuming code to project or further modify the results (paginate, etc.) to build an efficient query. Don't expose any method that you don't intend to get called. (Like a GetAll())
Edit: It sounds like you are trying to replace:
public async Task<Posts[]> GetPosts()
with
public async IQueryable<Post> GetPosts()
This is *not the objective. The objective is to centralize the core logic into a protected method which GetPosts as well as GetPaginatedResult can both call rather than having GetPaginatedResult calling GetPosts which is loading all data. You also need to address that you cannot call linkgenerator from within the Select expression without triggering client-side evaluation so the suggestion there is to either define view models for the results, or if you insist on returning the entity models as a view model, adding a non-mapped property for the generated URL.
public async Task<Posts[]> GetPosts()
{
return await _getPosts()
.Select(pts => new Posts
{
Postid = pts.Postid,
Title = pts.Title,
CategoryUrl = pts.CategoryNavigation.CategoryUrl,
SubcategoryUrl = pts.SubcategoryNavigation.SubcategoryUrl,
Subcategory2Url = pts.SubcategoryNavigation.Subcategory2Url
}).ToArrayAsync();
}
public async Task<List<Posts>> GetPaginatedResult(int currentPage, int pageSize)
{
return await _getPosts()
.Select(pts => new Posts
{
Postid = pts.Postid,
Title = pts.Title,
CategoryUrl = pts.CategoryNavigation.CategoryUrl,
SubcategoryUrl = pts.SubcategoryNavigation.SubcategoryUrl,
Subcategory2Url = pts.SubcategoryNavigation.Subcategory2Url
}).Skip((currentPage-1) * pageSize)
.Take(pageSize)
.ToListAsync();
}
Where _getPosts() is a new protected IQueryable method that centralizes the core rules around your isActive and Site. I put an Underscore before the method name to differentiate it from your public GetPosts() method which is probably called in a number of different places.
You initially want to avoid changing the signature of your public methods because this would break anywhere and everywhere else that called this method, where it is better to correct this issue a bit at a time where it is most needed.
Looking at your updated example you don't want to change your public methods to IQueryable, leave those as your original return types and just ensure that these methods that call the new IQueryable method do their respective await with ToArrayAsync or ToListAsync respectively instead of calling the public GetPosts() method. The change you will still need to make is to move ALL properties where you are calling "linkgenerator" or any similar C# objects/functions into unmapped properties and instead use Select to retrieve the raw values these calls will need.

ASP.NET Core Entity Framework SQL Query SELECT

I am one of the many struggling to "upgrade" from ASP.NET to ASP.NET Core.
In the ASP.NET project, I made database calls from my DAL like so:
var result = context.Database.SqlQuery<Object_VM>("EXEC [sp_Object_GetByKey] #Key",
new SqlParameter("#Key", Key))
.FirstOrDefault();
return result;
My viewmodel has additional fields that my object does not, such as aggregates of related tables. It seems unnecessary and counter intuitive to include such fields in a database / table structure. My stored procedure calculates all those things and returns the fields as should be displayed, but not stored.
I see that ASP.NET Core has removed this functionality. I am trying to continue to use stored procedures and load view models (and thus not have the entity in the database). I see options like the following, but as a result I get "2", the number of rows being returned (or another mysterious result?).
using(context)
{
string cmd = "EXEC [sp_Object_getAll]";
var result = context.Database.ExecuteSQLCommand(cmd);
}
But that won't work because context.Database.ExecuteSQLCommand is only for altering the database, not "selecting".
I've also seen the following as a solution, but the code will not compile for me, as "set" is really set<TEntity>, and there isn't a database entity for this viewmodel.
var result = context.Set().FromSql("EXEC [sp_Object_getAll]");
Any assistance much appreciated.
Solution:
(per Tseng's advice)
On the GitHub Entity Framework Issues page, there is a discussion about this problem. One user recommends creating your own class to handle this sort of requests, and another adds an additional method that makes it run smoother. I changed the methods slights to accept slightly different params.
Here is my adaptation (very little difference), for others that are also looking for a solution:
Method in DAL
public JsonResult GetObjectByID(int ID)
{
SqlParameter[] parms = new SqlParameter[] { new SqlParameter("#ID", ID) };
var result = RDFacadeExtensions.GetModelFromQuery<Object_List_VM>(context, "EXEC [sp_Object_GetList] #ID", parms);
return new JsonResult(result.ToList(), setting);
}
Additional Class
public static class RDFacadeExtensions
{
public static RelationalDataReader ExecuteSqlQuery(
this DatabaseFacade databaseFacade,
string sql,
SqlParameter[] parameters)
{
var concurrencyDetector = databaseFacade.GetService<IConcurrencyDetector>();
using (concurrencyDetector.EnterCriticalSection())
{
var rawSqlCommand = databaseFacade
.GetService<IRawSqlCommandBuilder>()
.Build(sql, parameters);
return rawSqlCommand
.RelationalCommand
.ExecuteReader(
databaseFacade.GetService<IRelationalConnection>(),
parameterValues: rawSqlCommand.ParameterValues);
}
}
public static IEnumerable<T> GetModelFromQuery<T>(
DbContext context,
string sql,
SqlParameter[] parameters)
where T : new()
{
DatabaseFacade databaseFacade = new DatabaseFacade(context);
using (DbDataReader dr = databaseFacade.ExecuteSqlQuery(sql, parameters).DbDataReader)
{
List<T> lst = new List<T>();
PropertyInfo[] props = typeof(T).GetProperties();
while (dr.Read())
{
T t = new T();
IEnumerable<string> actualNames = dr.GetColumnSchema().Select(o => o.ColumnName);
for (int i = 0; i < props.Length; ++i)
{
PropertyInfo pi = props[i];
if (!pi.CanWrite) continue;
System.ComponentModel.DataAnnotations.Schema.ColumnAttribute ca = pi.GetCustomAttribute(typeof(System.ComponentModel.DataAnnotations.Schema.ColumnAttribute)) as System.ComponentModel.DataAnnotations.Schema.ColumnAttribute;
string name = ca?.Name ?? pi.Name;
if (pi == null) continue;
if (!actualNames.Contains(name)) { continue; }
object value = dr[name];
Type pt = pi.DeclaringType;
bool nullable = pt.GetTypeInfo().IsGenericType && pt.GetGenericTypeDefinition() == typeof(Nullable<>);
if (value == DBNull.Value) { value = null; }
if (value == null && pt.GetTypeInfo().IsValueType && !nullable)
{ value = Activator.CreateInstance(pt); }
pi.SetValue(t, value);
}//for i
lst.Add(t);
}//while
return lst;
}//using dr
}

Is there a way to fill a listview in activity2 with info from a listview in activity1?

Activity 1 sends the info I want to Activity 2:
listView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> listView, View view,
int position, long id)
{
// Get the cursor, positioned to the corresponding row in the result set
Cursor cursor = (Cursor) listView.getItemAtPosition(position);
final int item_id = cursor.getInt(cursor.getColumnIndex(GamesDbAdapter.KEY_ROWID));
String item_cursus = cursor.getString(cursor.getColumnIndex(GamesDbAdapter.KEY_CURSUS));
String item_onderdeel = cursor.getString(cursor.getColumnIndex(GamesDbAdapter.KEY_ONDERDEEL));
String item_tijd = cursor.getString(cursor.getColumnIndex(GamesDbAdapter.KEY_TIJD));
String item_game = cursor.getString(cursor.getColumnIndex(GamesDbAdapter.KEY_GAME));
String item_web = cursor.getString(cursor.getColumnIndex(GamesDbAdapter.KEY_WEB));
Intent intent = new Intent(actGames_FRONT_ListViewCursorAdaptorActivity.this, actGames_ALL_ListViewCursorAdaptorActivity.class);
intent.putExtra("cursus", item_cursus);
intent.putExtra("id", item_id);
intent.putExtra("game", item_game);
startActivity(intent);
Toast done =
Toast.makeText(getApplicationContext(), item_game, Toast.LENGTH_LONG);
done.show();
}
});
In Activity2 I want to display "game" in another listview, but setText doesn't work with Listview.
game = (TextView)findViewById(R.id.game);
Intent iin= getIntent();
Bundle c = iin.getExtras();
if(c!=null)
{
String item_game =(String) c.get("game");
game.setText(item_game);
}
String game_list = getIntent().getExtras().getString("game");
This is the simplecursoradapter in activity2:
private void displayListView() {
Cursor cursor = dbHelper.fetchAllCursus();
// The desired columns to be bound
String[] cursus = new String[] {
GamesDbAdapter.KEY_CURSUS,
};
// the XML defined views which the data will be bound to
int[] to = new int[] {
R.id.front,
};
// create the adapter using the cursor pointing to the desired data
//as well as the layout information
dataAdapter = new SimpleCursorAdapter(
this, R.layout.games_row_front,
cursor,
cursus,
to,
0);
ListView listView = (ListView) findViewById(R.id.listView1);
// Assign adapter to ListView
listView.setAdapter(dataAdapter);
And this is in my DBadapter:
public Cursor fetchGames(){
String[] args = {"********************" };
Cursor mCursor = mDb.query(SQLITE_TABLE, null,
"cursus = ?" , args, KEY_GAME, null, null);
if (mCursor != null) {
mCursor.moveToFirst();
}
return mCursor;
}
When I replace the *** with a static item from the database it works but I can't get it to work with the intent from the first activity. Is there a way to fill a listview with info from another listview in another activity?

Where does IModel Apache Wicket retrieve an object?

First of all, please take a look at how IModel is used in this example:
#SuppressWarnings("serial")
public static List<IColumn> getTableColumns(
final ReportParams reportParams, final boolean columnsSortable
) {
List<IColumn> columns = new ArrayList<IColumn>();
final Map<String,ToolInfo> eventIdToolMap = Locator.getFacade().getEventRegistryService().getEventIdToolMap();
// site
if(Locator.getFacade().getReportManager().isReportColumnAvailable(reportParams, StatsManager.T_SITE)) {
columns.add(new PropertyColumn(new ResourceModel("th_site"), columnsSortable ? ReportsDataProvider.COL_SITE : null, ReportsDataProvider.COL_SITE) {
#Override
public void populateItem(Item item, String componentId, IModel model) {
final String site = ((Stat) model.getObject()).getSiteId();
String lbl = "", href = "";
Site s = null;
try{
s = Locator.getFacade().getSiteService().getSite(site);
lbl = s.getTitle();
href = s.getUrl();
}catch(IdUnusedException e){
lbl = (String) new ResourceModel("site_unknown").getObject();
href = null;
}
item.add(new ImageWithLink(componentId, null, href, lbl, "_parent"));
}
});
}
And my questions are:
How does populateItem get an input for IModel parameter?
I cannot find any code in this application, which explicitly constructs IModel object. Is it correct for me to assume that the object is retrieved directly from a table in the database? I'm thinking of this because Mapping Hibernate is used for this application.
The models are created using the IDataProvider you provide to the DataTable (DataTable constructor will also take your IColumn List) .
The IDataProvider could use Hibernate - hard to say without having more information on that implementation.

MVVM Change label foreground based on the value of the labels content

The content of my labels are bound to the VM and based on calculations will either be negative or positive. If they are positive I want the foreground to be a certain color and different color if they are negative. Should I just handle all this in the VM by binding the labels' foreground? There are only 4 labels btw.
Thanks
I would let the View handle how it displays the label. In my opinion, I would keep this color logic out of the ViewModel - as it should only handle business rules and such and not worry about how items are displayed.
XAML:
<sdk:Label Content="{Binding NumericValue}" Foreground="{Binding NumericValue, Converter={StaticResource numToColor}}" />
View Model:
private decimal _numValue = -1;
public decimal NumericValue
{
get { return _numValue; }
set
{
_numValue = value;
RaisePropertyChanged("NumericValue");
}
}
The Converter
public class NumberToColorConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null || !(value is decimal))
return new SolidColorBrush(Colors.Black);
var dValue = System.Convert.ToDecimal(value);
if (dValue < 0)
return new SolidColorBrush(Colors.Red);
else
return new SolidColorBrush(Colors.Green);
}
public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return null;
}
#endregion
}
I'm going to assume this is Silverlight or WPF
You need to create a ValueConverter. To do this you will need to create a new class that
implements the IValueConverter interface. The MSDN has a detailed explanation on how to do this.
Silverlight
http://msdn.microsoft.com/en-us/library/system.windows.data.ivalueconverter%28v=VS.95%29.aspx
WPF
http://msdn.microsoft.com/en-us/library/system.windows.data.ivalueconverter%28v=VS.100%29.aspx