DevExpress XtraScheduler hanging on adding appointment to Storage - devexpress

I have a XtraScheduler SchedulerControl configured as the following:
private DevExpress.XtraScheduler.SchedulerControl _SchedulerControl;
public DevExpress.XtraScheduler.SchedulerControl ConvSchedulerControl
{
get
{
if (_SchedulerControl == null)
{
_SchedulerControl = new DevExpress.XtraScheduler.SchedulerControl();
_SchedulerControl.Storage = new SchedulerStorage();
_SchedulerControl.Storage.Appointments.Mappings.Subject = "StandingOrderIDString";
_SchedulerControl.Storage.Appointments.Mappings.Start = "ScheduledDate";
_SchedulerControl.Storage.Appointments.Mappings.RecurrenceInfo = "RecurrenceInfo";
_SchedulerControl.Storage.Appointments.Mappings.Type = "Type";
_SchedulerControl.Storage.Appointments.CustomFieldMappings.Add(new DevExpress.XtraScheduler.AppointmentCustomFieldMapping("Inactive", "Inactive"));
_SchedulerControl.Storage.Appointments.CustomFieldMappings.Add(new DevExpress.XtraScheduler.AppointmentCustomFieldMapping("StandingOrderKEY", "StandingOrderKEY"));
BindingSource bs = new BindingSource();
bs.DataSource = new List<StandingOrder>();
_SchedulerControl.Storage.Appointments.DataSource = bs;
}
return _SchedulerControl;
}
}
and I am attempting to programmatically add an appointment with recurrence information, as in the examples given at http://help.devexpress.com/#WindowsForms/CustomDocument6201 . However, when the method execution reaches its final line (indicated) that adds the created appointment to the storage, it "hangs." No exception is ever thrown; I have left it running for upwards of 15 minutes with no change:
public void SetRecurrence(DateTime startDate, DateTime? endDate)
{
Appointment appointmentObj = ConvSchedulerControl.Storage.CreateAppointment(AppointmentType.Pattern);
if (endDate != null &&
endDate != DateTime.Parse("12/31/2999"))
{
appointmentObj.End = (DateTime)endDate;
}
else
{
appointmentObj.RecurrenceInfo.Range = RecurrenceRange.NoEndDate;
}
appointmentObj.Start = startDate;
appointmentObj.RecurrenceInfo.Type = RecurrenceType.Weekly;
appointmentObj.RecurrenceInfo.WeekDays = WeekDays.Monday;
appointmentObj.AllDay = true;
//Program execution reaches this line, but never proceeds past it.
ConvSchedulerControl.Storage.Appointments.Add(appointmentObj);
}
I would imagine that there's something wrong with the configuration that's preventing the storage from being able to successfully add the appointment, but I've been unable to turn up any other information on the subject. Does anyone know why this method isn't appropriate for adding an appointment to the storage, and how it can be corrected?

You've failed to provide a mapping for the 'End' field. This is a required mapping. Honestly, I only know this from having created a calendar in the designer. When you place a SchedulerControl onto a form/control, one of the things the designer gives you is a "Mappings Wizard". The 'Start' and 'End' fields are marked in the wizard as being required.

Related

Razor, ASP.NET Core, Entity Framework : updating some fields

I'm trying to update two entities at the same time but the change is not applying and I think that when I try to return the update entity it doesn't even found it.
Here is my Razor view:
public IActionResult OnPost()
{
if (!ModelState.IsValid)
{
return Page();
}
repositorioFamiliar.Actualizar(Familiar);
return RedirectToPage("/Familiares/DetalleFamiliar", new { IdPaciente = Familiar.IdPaciente });
}
Here is my update function:
public FamiliaresPer Actualizar(FamiliaresPer familiar)
{
var familiarActualizar = (from f in _context.Familiars.Where(p => p.IdFamiliar == familiar.IdFamiliar) select f).FirstOrDefault();
if (familiarActualizar != null)
{
familiarActualizar.Correo = familiar.Correo;
_context.Update(familiarActualizar);
_context.SaveChanges();
}
var personaActualizar = (from p in _context.Personas.Where(p => p.Id == familiar.IdPersona) select p).FirstOrDefault();
if (personaActualizar != null)
{
personaActualizar.Telefono = familiar.Telefono;
_context.Update(personaActualizar);
_context.SaveChanges();
}
var familiares = from p in _context.Familiars
from p1 in _context.Personas
where p.IdPaciente == familiar.IdPaciente
where p.IdPersona == p1.IdPersona
select new FamiliaresPer()
{
IdFamiliar = p.IdFamiliar,
IdPaciente = p.IdPaciente,
IdPersona = p1.IdPersona,
Id = p1.Id,
Nombres = p1.Nombres,
Apellidos = p1.Apellidos,
Genero = p1.Genero,
Telefono = p1.Telefono,
Parentesco = p.Parentesco,
Correo = p.Correo,
};
FamiliaresPer familiaresPer = familiares.FirstOrDefault();
return familiaresPer;
}
When I submit the form I get an error
NullReferenceException: Object reference not set to an instance of an object
And the link shows the IdPaciente = 0 when it should use the same IdPaciente of the updated entity (which the Id never changes).
In your OnPost( ) Action Method, you used repositorioFamiliar.Actualizar(Familiar);
but it looks like you didn't define 'Familiar'.
In addition, when I look at your code. I can give you an advice. Let's say your first update was done correctly and you got an error in the second update case. But you want both to be updated at the same time. Assume that the first object is updated in the database but the second one isn't. This is a problem, right? Unit of Work design pattern is very useful to solve this.
In brief, The approach should be to do SaveChanges() after both update processes are completed so there will be no changes in the database until both updates are completed.

I have a "Upload Record" PXAction to load records to grid and release these records

I have a custom PXbutton called UploadRecords, when I click this button I should populate the grid with records and release the records.
Release Action is pressed in the UploadRecords action delegate. The problem I get with this code is, the code here function properly for less records by release action but when passes thousands of records to release, it takes huge time(> 30 min.) and show the error like Execution timeout.
suggest me to avoid more execution time and release the records fastly.
namespace PX.Objects.AR
{
public class ARPriceWorksheetMaint_Extension : PXGraphExtension<ARPriceWorksheetMaint>
{
//public class string_R112 : Constant<string>
//{
// public string_R112()
// : base("4E5CCAFC-0957-4DB3-A4DA-2A24EA700047")
// {
// }
//}
public class string_R112 : Constant<string>
{
public string_R112()
: base("EA")
{
}
}
public PXSelectJoin<InventoryItem, InnerJoin<CSAnswers, On<InventoryItem.noteID, Equal<CSAnswers.refNoteID>>,
LeftJoin<INItemCost, On<InventoryItem.inventoryID, Equal<INItemCost.inventoryID>>>>,
Where<InventoryItem.salesUnit, Equal<string_R112>>> records;
public PXAction<ARPriceWorksheet> uploadRecord;
[PXUIField(DisplayName = "Upload Records", MapEnableRights = PXCacheRights.Select, MapViewRights = PXCacheRights.Select)]
[PXButton]
public IEnumerable UploadRecord(PXAdapter adapter)
{
using (PXTransactionScope ts = new PXTransactionScope())
{
foreach (PXResult<InventoryItem, CSAnswers, INItemCost> res in records.Select())
{
InventoryItem invItem = (InventoryItem)res;
INItemCost itemCost = (INItemCost)res;
CSAnswers csAnswer = (CSAnswers)res;
ARPriceWorksheetDetail gridDetail = new ARPriceWorksheetDetail();
gridDetail.PriceType = PriceTypeList.CustomerPriceClass;
gridDetail.PriceCode = csAnswer.AttributeID;
gridDetail.AlternateID = "";
gridDetail.InventoryID = invItem.InventoryID;
gridDetail.Description = invItem.Descr;
gridDetail.UOM = "EA";
gridDetail.SiteID = 6;
InventoryItemExt invExt = PXCache<InventoryItem>.GetExtension<InventoryItemExt>(invItem);
decimal y;
if (decimal.TryParse(csAnswer.Value, out y))
{
y = decimal.Parse(csAnswer.Value);
}
else
y = decimal.Parse(csAnswer.Value.Replace(" ", ""));
gridDetail.CurrentPrice = y; //(invExt.UsrMarketCost ?? 0m) * (Math.Round(y / 100, 2));
gridDetail.PendingPrice = y; // (invExt.UsrMarketCost ?? 0m)* (Math.Round( y/ 100, 2));
gridDetail.TaxID = null;
Base.Details.Update(gridDetail);
}
ts.Complete();
}
Base.Document.Current.Hold = false;
using (PXTransactionScope ts = new PXTransactionScope())
{
Base.Release.Press();
ts.Complete();
}
List<ARPriceWorksheet> lst = new List<ARPriceWorksheet>
{
Base.Document.Current
};
return lst;
}
protected void ARPriceWorksheet_RowSelected(PXCache cache, PXRowSelectedEventArgs e, PXRowSelected InvokeBaseHandler)
{
if (InvokeBaseHandler != null)
InvokeBaseHandler(cache, e);
var row = (ARPriceWorksheet)e.Row;
uploadRecord.SetEnabled(row.Status != SPWorksheetStatus.Released);
}
}
}
First, Do you need them all to be in a single transaction scope? This would revert all changes if there is an exception in any. If you need to have them all committed without any errors rather than each record, you would have to perform the updates this way.
I would suggest though moving your process to a custom processing screen. This way you can load the records, select one or many, and use the processing engine built into Acumatica to handle the process, rather than a single button click action. Here is an example: https://www.acumatica.com/blog/creating-custom-processing-screens-in-acumatica/
Based on the feedback that it must be all in a single transaction scope and thousands of records, I can only see two optimizations that may assist. First is increasing the Timeout as explained in this blog post. https://acumaticaclouderp.blogspot.com/2017/12/acumatica-snapshots-uploading-and.html
Next I would load all records into memory first and then loop through them with a ToList(). That might save you time as it should pull all records at once rather than once for each record.
going from
foreach (PXResult<InventoryItem, CSAnswers, INItemCost> res in records.Select())
to
var recordList = records.Select().ToList();
foreach (PXResult<InventoryItem, CSAnswers, INItemCost> res in recordList)

WF 4 Rehosted Designer - get foreach InArgument Value

After reading this article:
http://blogs.msdn.com/b/tilovell/archive/2009/12/29/the-trouble-with-system-activities-foreach-and-parallelforeach.aspx
I have defined the ForEachFactory as follows:
public class ForEachFactory<T> : IActivityTemplateFactory
{
public Activity Create(DependencyObject target)
{
return new ForEach<T>
{
DisplayName = "ForEachFromFactory",
Body = new ActivityAction<T>
{
Argument = new DelegateInArgument<T>("item")
}
};
}
}
All works well but is it possible to check how that DelegeateInArgument in my case named "item" changes its value ?
So if i have defined an array in the variables section and initialized with
{1, 2, 3} i need a way to check how the "item" takes value 1, 2 and then 3.
To be more accurate, i've added this pic, with a breakpoint on the WriteLine activity inside the foreach. When the execution will stop there, is there a way to find out what the value of item is ?
EDIT 1:
Possible solution in my case:
After struggling a bit more i found one interesting thing:
Adding one of my custom activities in the Body of the ForEach, i am able to get the value of the item like this :
So, my activity derives from : CodeActivity
Inside the protected override String[] Execute(CodeActivityContext context) i am doing this job.To be honest, this solves the thing somehow, but it is doable only in my custom activities. If i would put a WriteLine there for example, i would not be able to retrieve that value.
you can access the DelegeateInArgument of a ForEach activity by inspecting the ModelItem trees parent and checking for DelegeateInArgument's. If you need a specific code example to achieve this I may need a some time to code the example. As it has been a long time since I did this, see my question i asked over on msdn
So basically where your break point is, you can access the variable values as these are defined with n the scope of your activity as 'variables'. However the 'item' variable is actually only accessible from the parent loop activity. So you have to get the model item of the current executing activity and then traverse up the tree to find the parent containing the desired DelegateInArgument.
Can you flesh out exactly what you want to achieve? Is it that when your debugging the workflow in the re-hosted designer you want to display the variable values to the user as they change in the UI?
Edit - added tracking example
So as your wanting to display the variable values during execution of the workflow we need to use tracking to achieve this. In the example your using the author has already implemented some basic tracking. So to achieve the extended variable tracking you want you will need to alter the tracking profile.
Firstly amend the WorkflowDesignerHost.xaml.cs file alter the RunWorkflow method to define the SimulatorTrackingParticipant as below.
SimulatorTrackingParticipant simTracker = new SimulatorTrackingParticipant()
{
TrackingProfile = new TrackingProfile()
{
Name = "CustomTrackingProfile",
Queries =
{
new CustomTrackingQuery()
{
Name = all,
ActivityName = all
},
new WorkflowInstanceQuery()
{
**States = {all },**
},
new ActivityStateQuery()
{
// Subscribe for track records from all activities for all states
ActivityName = all,
States = { all },
**Arguments = {all},**
// Extract workflow variables and arguments as a part of the activity tracking record
// VariableName = "*" allows for extraction of all variables in the scope
// of the activity
Variables =
{
{ all }
}
}
}
}
};
This will now correctly capture all workflow instance states rather than just Started/Completed. You will also capture all Arguments on each activity that records tracking data rather than just the variables. This is important because the 'variable' were interested in is actually (as discussed earlier) a DelegateInArgument.
So once we have changed the tracking profile we also need to change the SimulatorTrackingParticipant.cs to extract the additional data we are now tracking.
If you change the OnTrackingRecordReceived method to include the following sections these will capture variable data and also Argument data during execution.
protected void OnTrackingRecordReceived(TrackingRecord record, TimeSpan timeout)
{
System.Diagnostics.Debug.WriteLine(
String.Format("Tracking Record Received: {0} with timeout: {1} seconds.", record, timeout.TotalSeconds)
);
if (TrackingRecordReceived != null)
{
ActivityStateRecord activityStateRecord = record as ActivityStateRecord;
if (activityStateRecord != null)
{
IDictionary<string, object> variables = activityStateRecord.Variables;
StringBuilder vars = new StringBuilder();
if (variables.Count > 0)
{
vars.AppendLine("\n\tVariables:");
foreach (KeyValuePair<string, object> variable in variables)
{
vars.AppendLine(String.Format(
"\t\tName: {0} Value: {1}", variable.Key, variable.Value));
}
}
}
if (activityStateRecord != null)
{
IDictionary<string, object> arguments = activityStateRecord.Arguments;
StringBuilder args = new StringBuilder();
if (arguments.Count > 0)
{
args.AppendLine("\n\tArgument:");
foreach (KeyValuePair<string, object> argument in arguments)
{
args.AppendLine(String.Format(
"\t\tName: {0} Value: {1}", argument.Key, argument.Value));
}
}
//bubble up the args to the UI for the user to see!
}
if((activityStateRecord != null) && (!activityStateRecord.Activity.TypeName.Contains("System.Activities.Expressions")))
{
if (ActivityIdToWorkflowElementMap.ContainsKey(activityStateRecord.Activity.Id))
{
TrackingRecordReceived(this, new TrackingEventArgs(
record,
timeout,
ActivityIdToWorkflowElementMap[activityStateRecord.Activity.Id]
)
);
}
}
else
{
TrackingRecordReceived(this, new TrackingEventArgs(record, timeout,null));
}
}
}
Hope this helps!

ASP.NET MVC 4 Custom Action filters with dynamic data

So I am building a web application that I want to sell once Im done with it. It allows the user to enter data such as their website name, meta keywords, their contact email, phone, address etc in the admin panel. I wrote a Action Filter in order to include these values in every request that I put the filter on so I didnt have to query for them every time because these values are included in the common footer throughout the site. However, I learned that if I update the database with new or different information for these values, it does not update on the web pages which im guessing is because Action Filters are configured at application start up. In the Action Filter I am using a repository pattern to query for these values. I have included the code for the action filter below. How can I have the convenience of the Action Filter but be able to update it dynamically when the data changes in the database? Thanks!
public class ViewBagActionFilter : ActionFilterAttribute,IActionFilter
{
Repositories.SettingsRepository _repo = new Repositories.SettingsRepository();
void IActionFilter.OnActionExecuted(ActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
}
void IActionFilter.OnActionExecuting(ActionExecutingContext filterContext)
{
string siteName = _repo.GetSiteName();
string siteDesc = _repo.GetSiteDescription();
string siteKeywords = _repo.GetSiteKeywords();
string googleAnalytics = _repo.GetGoogleAnalytics();
string streetAddress = _repo.GetStreetAddress();
string zipCode = _repo.GetZipCode();
string city = _repo.GetCity();
string state = _repo.GetState();
string aboutUs = _repo.GetAboutUs();
string phone = _repo.GetPhoneNumber();
string contactEmail = _repo.GetContactEmail();
if (!string.IsNullOrWhiteSpace(siteName) && siteName.Length > 0)
{
string[] splitSiteName = new string[siteName.Length/2];
splitSiteName = siteName.Split(' ');
if (splitSiteName.Length > 1)
{
filterContext.Controller.ViewBag.SiteName1 = splitSiteName[0];
filterContext.Controller.ViewBag.SiteName2 = splitSiteName[1];
}
else
{
filterContext.Controller.ViewBag.SiteName1 = splitSiteName[0];
filterContext.Controller.ViewBag.SiteName2 = "";
}
}
//Set default values for common viewbag items that are on every page using ternary syntax
filterContext.Controller.ViewBag.SiteDescription = (!string.IsNullOrWhiteSpace(siteDesc) && siteDesc.Length > 0) ? siteDesc : "";
filterContext.Controller.ViewBag.SiteKeywords = (!string.IsNullOrWhiteSpace(siteKeywords) && siteKeywords.Length > 0) ? siteKeywords : "";
filterContext.Controller.ViewBag.GoogleAnalytics = (!string.IsNullOrWhiteSpace(googleAnalytics) && googleAnalytics.Length > 0) ? googleAnalytics : "";
filterContext.Controller.ViewBag.StreetAddress = (!string.IsNullOrWhiteSpace(streetAddress) && streetAddress.Length > 0) ? streetAddress : "";
filterContext.Controller.ViewBag.ZipCode = (!string.IsNullOrWhiteSpace(zipCode) && zipCode.Length > 0) ? zipCode : "";
filterContext.Controller.ViewBag.City = (!string.IsNullOrWhiteSpace(city) && city.Length > 0) ? city : "";
filterContext.Controller.ViewBag.State = (!string.IsNullOrWhiteSpace(state) && state.Length > 0) ? state : "";
filterContext.Controller.ViewBag.AboutUs = (!string.IsNullOrWhiteSpace(aboutUs) && aboutUs.Length > 0) ? aboutUs : "";
filterContext.Controller.ViewBag.PhoneNumber = (!string.IsNullOrWhiteSpace(phone) && phone.Length > 0) ? phone : "";
filterContext.Controller.ViewBag.ContactEmail = (!string.IsNullOrWhiteSpace(contactEmail) && contactEmail.Length > 0) ? contactEmail : "";
base.OnActionExecuting(filterContext);
}
}
I will try to explain how action filters works.
So if you extend Action filter you can override 4 base methods :
OnActionExecuting – This method is called before a controller action is executed.
OnActionExecuted – This method is called after a controller action is executed.
OnResultExecuting – This method is called before a controller action result is executed.
OnResultExecuted – This method is called after a controller action result is executed.
So thats mean that you method will be called each time before Controller will run action.
Now about optimization. You have
string siteName = _repo.GetSiteName();
string siteDesc = _repo.GetSiteDescription();
string siteKeywords = _repo.GetSiteKeywords();
string googleAnalytics = _repo.GetGoogleAnalytics();
string streetAddress = _repo.GetStreetAddress();
string zipCode = _repo.GetZipCode();
string city = _repo.GetCity();
string state = _repo.GetState();
string aboutUs = _repo.GetAboutUs();
string phone = _repo.GetPhoneNumber();
string contactEmail = _repo.GetContactEmail();
I would suggest you to create one class
public class Site{
public string SiteName{get;set;}
public string City{get;set;}
//And so on just to add all properties
}
then in repository add one more method
_repo.GetSite(); //Which will return object Site
Then
filterContext.Controller.ViewBag.CurrentSite = _repo.GetSite();
And now probably the most important for you. Why it doesnot work as you want and its a bit simple. Attribute class is initialized only once on Application start and after that it doesnot reloads, and your implementation is a bit strange since
Repositories.SettingsRepository _repo = new Repositories.SettingsRepository();
I suppose here you are loading settings. So after you load you did not reload it anymore... thats mean you will get same result each time you reload page, but if you restart iis for instance you will refresh data.
Possible solution
Move initialization of _repo to OnActionExecuting then it will reload data each time, or rewrite repository as i suggested and
filterContext.Controller.ViewBag.CurrentSite = _repo.GetSite();
Should always load new data from db.
Hope it helps :)

Application Cache and Slow Process

I want to create an application wide feed on my ASP.net 3.5 web site using the application cache. The data that I am using to populate the cache is slow to obtain, maybe up to 10 seconds (from a remote server's data feed). My question/confusion is, what is the best way to structure the cache management.
private const string CacheKey = "MyCachedString";
private static string lockString = "";
public string GetCachedString()
{
string data = (string)Cache[CacheKey];
string newData = "";
if (data == null)
{
// A - Should this method call go here?
newData = SlowResourceMethod();
lock (lockString)
{
data = (string)Cache[CacheKey];
if (data != null)
{
return data;
}
// B - Or here, within the lock?
newData = SlowResourceMethod();
Cache[CacheKey] = data = newData;
}
}
return data;
}
The actual method would be presented by and HttpHandler (.ashx).
If I collect the data at point 'A', I keep the lock time short, but might end up calling the external resource many times (from web pages all trying to reference the feed). If I put it at point 'B', the lock time will be long, which I am assuming is a bad thing.
What is the best approach, or is there a better pattern that I could use?
Any advice would be appreciated.
I add the comments on the code.
private const string CacheKey = "MyCachedString";
private static readonly object syncLock = new object();
public string GetCachedString()
{
string data = (string)Cache[CacheKey];
string newData = "";
// start to check if you have it on cache
if (data == null)
{
// A - Should this method call go here?
// absolut not here
// newData = SlowResourceMethod();
// we are now here and wait for someone else to make it or not
lock (syncLock)
{
// now lets see if some one else make it...
data = (string)Cache[CacheKey];
// we have it, send it
if (data != null)
{
return data;
}
// not have it, now is the time to look for it.
// B - Or here, within the lock?
newData = SlowResourceMethod();
// set it on cache
Cache[CacheKey] = data = newData;
}
}
return data;
}
Better for me is to use mutex and lock depended on the name CacheKey and not lock all resource and the non relative one. With mutex one basic simple example will be:
private const string CacheKey = "MyCachedString";
public string GetCachedString()
{
string data = (string)Cache[CacheKey];
string newData = "";
// start to check if you have it on cache
if (data == null)
{
// lock it base on resource key
// (note that not all chars are valid for name)
var mut = new Mutex(true, CacheKey);
try
{
// Wait until it is safe to enter.
// but also add 30 seconds max
mut.WaitOne(30000);
// now lets see if some one else make it...
data = (string)Cache[CacheKey];
// we have it, send it
if (data != null)
{
return data;
}
// not have it, now is the time to look for it.
// B - Or here, within the lock?
newData = SlowResourceMethod();
// set it on cache
Cache[CacheKey] = data = newData;
}
finally
{
// Release the Mutex.
mut.ReleaseMutex();
}
}
return data;
}
You can also read
Image caching issue by using files in ASP.NET

Resources