I have a tracking participant which, when called, fires off a new thread to do the tracking work. The tracking work eventually does this:
private static readonly ConcurrentDictionary<string, DateTime> TimingsDictionary = new ConcurrentDictionary<string, DateTime>();
private static readonly ConcurrentDictionary<Guid, DateTime> WorkflowTimingsDictionary = new ConcurrentDictionary<Guid, DateTime>();
private void TimeActivityRecord(TrackingRecord record)
{
var activityStateRecord = record as ActivityStateRecord;
if (activityStateRecord != null)
{
if (activityStateRecord.State == ActivityStates.Executing)
{
if (!TimingsDictionary.TryAdd(GetActivityId(activityStateRecord), activityStateRecord.EventTime))
{}
}
if (activityStateRecord.State == ActivityStates.Closed
|| activityStateRecord.State == ActivityStates.Faulted
|| activityStateRecord.State == ActivityStates.Canceled)
{
DateTime startTime;
if (TimingsDictionary.TryRemove(GetActivityId(activityStateRecord), out startTime))
{
timer.TimeAction("Executing workflow step " + activityStateRecord.Activity.Name, activityStateRecord.InstanceId, activityStateRecord.EventTime.Subtract(startTime));
}
}
}
}
private void TimeWorkflowRecords(TrackingRecord record)
{
var workflowInstanceRecord = record as WorkflowInstanceRecord;
if (workflowInstanceRecord != null)
{
if (workflowInstanceRecord.State == WorkflowInstanceStates.Started)
{
if (!WorkflowTimingsDictionary.TryAdd(workflowInstanceRecord.InstanceId, workflowInstanceRecord.EventTime))
{}
}
if (workflowInstanceRecord.State == WorkflowInstanceStates.Completed
|| workflowInstanceRecord.State == WorkflowInstanceStates.Aborted
|| workflowInstanceRecord.State == WorkflowInstanceStates.UnhandledException
|| workflowInstanceRecord.State == WorkflowInstanceStates.Terminated
|| workflowInstanceRecord.State == WorkflowInstanceStates.Canceled)
{
DateTime startTime;
if (WorkflowTimingsDictionary.TryRemove(workflowInstanceRecord.InstanceId, out startTime))
{
timer.TimeAction("Executing workflow", workflowInstanceRecord.InstanceId, workflowInstanceRecord.EventTime.Subtract(startTime));
}
}
}
}
to track the entire workflow time and the times of the configured activities. however I get strange results with the workflow instance itself always seeming to take less time than the longest activity. sometimes I get the workflow taking 16ms and the 6 activities within it taking 625ms, 150ms, 125ms, 93ms, 17ms, 78ms.
Am I doing something very wrong? I feel like I must be missing something very obvious but can't for the life of me see what it is.
of course I was doing something stupid. When I logged the time taken from the timespan I was using
timespan.Milliseconds
rather than
timespan.TotalMilliseconds
back to school for me. Or maybe just some sleep.
Related
Scenario:
User submits search criteria and selects an item from search results on the same page, which navigates to a new page of details for the selected item.
When the User returns to the search screen, the search criteria & results (including selected page and sort-order) should be preserved from their last visit.
Related information:
All form submissions are POSTs.
Navigation back to the search screen may not be available from last browser history (e.g. more than one details screen may be encountered, or the user may navigate directly to the search screen from an alternative menu.)
Search results are provided using Telerik RadGrid control.
I'm looking for a generic solution that will be able to be applied to different search screens.
In some instances, the item may be DELETED from within the details screen, and should therefore not appear in the search results when the screen is next encountered.
Thoughts:
I've read a lot of suggested methods for addressing various parts of this scenario, but I'm still confused; no comprehensively "correct" solution jumps to the forefront.
I guess I'm asking for recommendations/approach rather than a whole solution spelled out for me (although that would be nice! ;-)
The .NET VIEWSTATE would seem to do exactly what I'm after (with the exception of #5) - Is there some way of leveraging off this so that viewstate can be used between pages, and not just between postbacks to the same page? (e.g. can I store/restore viewstate to/from a session variable or something? I haven't seen this suggested anywhere and I'm wondering if there's a reason why.)
Thanks in advance.
Thanks for all the advice.
For the benefit of others, here is a solution to this issue (no doubt there's room for improvement, but this works satisfactorily for the moment).
4 functions...
StoreSearchCookie - Persist the state/values of a panel of search criteria and a results grid in a cookie with a specified UID.
RestoreSearchCookie_Criteria - Read the cookie and re-populate the search criteira
RestoreSearchCookie_Results - Read the cookie and restore the grid state.
FindFormControls - Helper method to recursively find form-input controls in a container (pinched & modified from elsewhere on Stack Overflow)
NB...
I haven't addressed the multiple-tabs issue because our application doesn't allow them anyway.
RestoreSearchResults utilises GridSettingsPersister.cs available from Telerik website, (but I had to modify it to store the page number as well)
Usage is as follows...
protected void Page_PreRender(object sender, EventArgs e)
{
if (Page.IsPostBack)
{
// Store the state of the page
StoreSearchCookie("SomeSearchPage", pnlSearchCriteria, gridResults);
}
else
{
// Restore search criteria
RestoreSearchCookie_Criteria("SomeSearchPage");
// Re-invoke the search here
DoSearch(); // (for example)
// Restore the grid state
RestoreSearchCookie_Results("SomeSearchPage");
}
}
Code follows...
protected void StoreSearchCookie(string cookieName, Panel SearchPanel, RadGrid ResultsGrid)
{
try
{
HttpCookie cookieCriteria = new HttpCookie("StoredSearchCriteria_" + cookieName);
// 1. Store the search criteria
//
List<Control> controls = new List<Control>();
FindFormControls(controls, SearchPanel);
foreach (Control control in controls)
{
string id = control.ID;
string parentId = control.Parent.ID;
string uid = string.Format("{0}>{1}", parentId, id);
string value = "";
Type type = control.GetType();
bool isValidType = true; // Optimistic!
if (type == typeof(TextBox))
{
value = ((TextBox)control).Text;
}
else if (type == typeof(DropDownList))
{
value = ((DropDownList)control).SelectedValue;
}
else if (type == typeof(HiddenField))
{
value = ((HiddenField)control).Value;
}
else if (type == typeof(RadioButton))
{
value = ((RadioButton)control).Checked.ToString();
}
else if (type == typeof(CheckBox))
{
value = ((CheckBox)control).Checked.ToString();
}
else
{
isValidType = false;
}
if (isValidType)
{
cookieCriteria.Values[uid] = value;
}
}
cookieCriteria.Expires = DateTime.Now.AddDays(1d);
Response.Cookies.Add(cookieCriteria);
// 2. Persist the grid settings
//
GridSettingsPersister SavePersister = new GridSettingsPersister(ResultsGrid);
HttpCookie cookieResults = new HttpCookie("StoredSearchResults_" + cookieName);
cookieResults.Values["GridId"] = ResultsGrid.ID;
cookieResults.Values["GridSettings"] = SavePersister.SaveSettings();
cookieResults.Expires = DateTime.Now.AddDays(1d);
Response.Cookies.Add(cookieResults);
}
catch (Exception exception)
{
Logger.Write(exception);
}
}
protected void RestoreSearchCookie_Criteria(string cookieName)
{
try
{
HttpCookie cookieCriteria = Request.Cookies["StoredSearchCriteria_" + cookieName];
if (cookieCriteria != null)
{
foreach (string key in cookieCriteria.Values.AllKeys)
{
string value = cookieCriteria[key];
string[] ids = key.Split('>');
string parentId = ids[0];
string id = ids[1];
Control control = FindControl(parentId).FindControl(id);
Type type = control.GetType();
if (type == typeof(TextBox))
{
((TextBox)control).Text = value;
}
else if (type == typeof(DropDownList))
{
((DropDownList)control).SelectByValue(value);
}
else if (type == typeof(HiddenField))
{
((HiddenField)control).Value = value;
}
else if (type == typeof(RadioButton))
{
((RadioButton)control).Checked = Boolean.Parse(value);
}
else if (type == typeof(CheckBox))
{
((CheckBox)control).Checked = Boolean.Parse(value);
}
}
}
}
catch (Exception exception)
{
Logger.Write(exception);
}
}
protected void RestoreSearchCookie_Results(string cookieName)
{
try
{
HttpCookie cookieResults = Request.Cookies["StoredSearchResults_" + cookieName];
if (cookieResults != null)
{
string gridId = cookieResults.Values["GridId"];
string settings = cookieResults.Values["GridSettings"];
RadGrid grid = (RadGrid)FindControl(gridId);
GridSettingsPersister LoadPersister = new GridSettingsPersister(grid);
LoadPersister.LoadSettings(settings);
grid.Rebind();
}
}
catch (Exception exception)
{
Logger.Write(exception);
}
}
private void FindFormControls(List<Control> foundSofar, Control parent)
{
List<Type> types = new List<Type> { typeof(TextBox), typeof(DropDownList), typeof(RadioButton), typeof(CheckBox), typeof(HiddenField) };
foreach (Control control in parent.Controls)
{
if (types.Any(item => item == control.GetType()))
{
foundSofar.Add(control);
}
if (control.Controls.Count > 0)
{
this.FindFormControls(foundSofar, control); // Use recursion to find all descendants.
}
}
}
I have a static method in a helper class named helper.getdiscount(). This class is ASP.NET frontend code and used by UI pages.
Inside this method I check if some data is in the ASP.NET cache then return it, otherwise it makes a service call and store the result in the cache and then returns that value.
Will this be a problem considering multiple threads might be accessing it at the same time?
if (HttpContext.Current.Cache["GenRebateDiscountPercentage"] == null)
{
IShoppingService service = ServiceFactory.Instance.GetService<IShoppingService>();
rebateDiscountPercentage= service.GetGenRebateDiscountPercentage().Result;
if (rebateDiscountPercentage > 0)
{
HttpContext.Current.Cache.Add("GenRebateDiscountPercentage", rebateDiscountPercentage, null, DateTime.Now.AddDays(1), System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.Normal, null);
}
}
else
{
decimal.TryParse(HttpContext.Current.Cache["GenRebateDiscountPercentage"].ToString(), out rebateDiscountPercentage);
}
Please advise if this is fine or any better approach could be used.
try something like this with lock object.
static readonly object objectToBeLocked= new object();
lock( objectToBeLocked)
{
if (HttpContext.Current.Cache["GenRebateDiscountPercentage"] == null)
{
IShoppingService service = ServiceFactory.Instance.GetService<IShoppingService>();
rebateDiscountPercentage= service.GetGenRebateDiscountPercentage().Result;
if (rebateDiscountPercentage > 0)
{
HttpContext.Current.Cache.Add("GenRebateDiscountPercentage", rebateDiscountPercentage, null, DateTime.Now.AddDays(1), System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.Normal, null);
}
}
else
{
decimal.TryParse(HttpContext.Current.Cache["GenRebateDiscountPercentage"].ToString(), out rebateDiscountPercentage);
}
}
Also you can look into following thread.
What is the best way to lock cache in asp.net?
Use these generic methods to use the cache for any type:
`public static void AddCache(string key, object Data, int minutesToLive = 1440)
{
if (Data == null)
return;
HttpContext.Current.Cache.Insert(key, Data, null, DateTime.Now.AddMinutes(minutesToLive), Cache.NoSlidingExpiration);
}
public static T GetCache<T>(string key)
{
return (T)HttpContext.Current.Cache.Get(key);
} `
Now to solve your problem:
`if(GetCache<decimal>("GenRebateDiscountPercentage") == null)
{
IShoppingService service = ServiceFactory.Instance.GetService<IShoppingService>();
rebateDiscountPercentage= service.GetGenRebateDiscountPercentage().Result;
if (rebateDiscountPercentage > 0)
{
AddCache("GetGenRebateDiscountPercentage", rebateDiscountPercentage);
}
}
else
{
rebateDiscountPercentage = GetCache<decimal>("GetGenRebateDiscountPercentage");
}
`
I'm developing an Android APP that connects to Google Calendar using GData API for Google Calendar in Java. So far I've managed to create events but I could only set the title, description and time.
Does anybody know where I can find a reference or a sample with all the parameters I can set to an event?
I leave you some code of what I've achieved so far.
CalendarService calendarService = new CalendarService("CalendarAPP");
calendarService.setUserCredentials(<username>, <password>);
URL postUrl = new URL("https://www.google.com/calendar/feeds/<GMAIL ACCOUNT>/private/full");
CalendarEventEntry myEntry = new CalendarEventEntry();
myEntry.setTitle(new PlainTextConstruct("Tennis with Beth"));
myEntry.setContent(new PlainTextConstruct("Meet for a quick lesson."));
DateTime startTime = DateTime.now();
DateTime endTime = DateTime.now();
When eventTimes = new When();
eventTimes.setStartTime(startTime);
eventTimes.setEndTime(endTime);
myEntry.addTime(eventTimes);
CalendarEventEntry insertedEntry = connection.getCalendarService().insert(postUrl, myEntry);
Thanks in advance.
Mikywan.
GData for Google Calendar it's pretty damn good. For every property you may want to set or get, there is a Getter and a Setter defined. You just have to look for the setter/getter on the event entry that suits the data you want access.
I leave an example of how to show on the console almost all the data you may want to.
Enjoy!
private static void showCalendarEventEntry(CalendarEventEntry entry) {
assert entry != null;
System.out.println("-------------------------------------------");
System.out.println("START showCalendarEventEntry");
System.out.println("");
System.out.println("ID: " + entry.getId());
System.out.println("TITLE: "+entry.getTitle().getPlainText());
System.out.println("DESCRIPTION: "+entry.getPlainTextContent());
System.out.println("LOCATION: "+entry.getLocations().get(0).getValueString());
System.out.println("");
System.out.println("TIMES");
if (entry.getTimes().size() > 0) {
When eventTimes = entry.getTimes().get(0);
if (eventTimes.getStartTime().isDateOnly()) {
System.out.println("\tWHEN: ALL DAY");
} else {
System.out.println("\tWHEN: TIME");
}
if (entry.getRecurrence() != null)
System.out.println("\tRECURRENCE: "+entry.getRecurrence().toString());
System.out.println("\tSTART TIME: "+eventTimes.getStartTime());
System.out.println("\tEND TIME: "+eventTimes.getEndTime());
}
System.out.println("");
System.out.println("PARTICIPANTS");
System.out.println("\t"+(entry.getParticipants().size()) + " PARTICIPANTS");
if (entry.getParticipants().size() > 0){
for (int i=0; i<entry.getParticipants().size(); i++) {
EventWho participant = entry.getParticipants().get(i);
System.out.println("\t\tPARTICIPANT "+participant.getValueString());
System.out.println("\t\t\tTYPE: "+participant.getAttendeeType());
System.out.println("\t\t\tSTATUS: "+participant.getAttendeeStatus());
}
if (entry.isGuestsCanInviteOthers())
System.out.println("\tGUESTS CAN INVITE OTHERS: ");
if (entry.isGuestsCanModify())
System.out.println("\tGUESTS CAN MODIFY");
if (entry.isGuestsCanSeeGuests())
System.out.println("\tGUESTS CAN SEE GUESTS");
}
//REMINDERS
System.out.println("");
System.out.println("REMINDERS");
System.out.println("\t"+entry.getReminder().size()+" REMINDERS");
if (entry.getReminder().size() > 0) {
for (int i=0; i<entry.getReminder().size(); i++) {
Reminder reminder = entry.getReminder().get(i);
System.out.println("\t\tREMINDER "+i);
System.out.println("\t\t\tMETHOD: "+reminder.getMethod().toString());
System.out.println("\t\t\tDAYS: "+reminder.getDays());
System.out.println("\t\t\tHOURS: "+reminder.getHours());
System.out.println("\t\t\tMINUTES: "+reminder.getMinutes());
}
}
//VISIBILITY
System.out.println("");
System.out.println("VISIBILITY: "+entry.getVisibility().getValue());
System.out.println("");
System.out.println("END showCalendarEventEntry");
System.out.println("-------------------------------------------");
}
If I have a read-only property on an object that fills itself via the DB, is this what I should be doing, or is there a better way to make sure it's already been evaluated?
private List<Variable> _selectedVariables;
public new List<Variable> SelectedVariables
{
get
{
if (_selectedVariables == null)
{
_selectedVariables = SomeFunctionThatCallsDB();
}
return _selectedVariables;
}
}
That's fine for a single thread; but you will have problems if that is going to be in a situation where you have multithreaded gets.
EDIT: Threadsafing:
Simple Threadsafe pattern:
private readonly object _objectLock = new object();
private List<T> _someList = null;
public List<T> MyStuff
{
get
{
if(_someList == null)
{
lock(_objectLock)
{
if(_someList == null)
_someList = LoadFromDB();
}
}
return _someList;
}
}
You check to see if set, then lock, then check again to make sure you covered the race condition.
I have a multiple web sits asp.net application.
In this application different domains using the same pages.
All pages inherit from base class named: PageBase
wich inherit from System.Web.UI.Page.
By using: HttpContext.Current.Request.ServerVariables["HTTP_HOST"]
i cen determine what is the domain and then get all the info i need
for this domain and everything is working good.
My problem begin when i want to use different visitor counter for each site based on session.
Because Global.asax have Global events:
Session_Start
Session_End
simple counter will count all visitors on all sites together.
I try to make code behind for the Global.asax in different class
but i cold not get in that class the PageBase(System.Web.UI.Page) web site info.
I will be very thankful for any ideas to solve this problem
cheinan
I am assuming that you are able to browse from one "site" to the other within the same session and that there is only one session created.
In this case, you need to add the following to your Session:
Session["CountedHosts"] = new List<string>();
Then, on your base page, add the following:
var host = Request.ServerVariables["HTTP_HOST"];
var countedHosts = Session["CountedHosts"] as List<string>;
if (countedHosts != null && !countedHosts.Contains(host))
{
countedHosts.Add(host);
}
Then on session end, record each host that was visited.
var countedHosts = Session["CountedHosts"] as List<string>;
if (countedHosts != null)
{
foreach (var host in countedHosts)
{
//Log it
}
}
I am not able to browse from one "site" to the other within the same session each site have is on
different session created.
but i am very thankful to you because you gave me en idea
how to solv this problem
here is what i did:
i created counter class with Dictionary "onlineList" were i automatic creat for each site a key:
public abstract class counter{
public static Dictionary<string, int> onlineList = new Dictionary<string, int>();
//do add one count
public static void doSiteCountOn(string siteID)
{
if (onlineList.ContainsKey(siteID))
{
onlineList[siteID] += 1;
}
else
{
onlineList.Add(siteID, 1);
}
}
//do less one count
public static void doSiteCountOff(string siteID)
{
if (onlineList.ContainsKey(siteID))
{
onlineList[siteID] -= 1;
}
else
{
onlineList.Add(siteID, 0);
}
}
//get the count
public static string onlineCount(string siteID)
{
if (onlineList.ContainsKey(siteID))
{
return onlineList[siteID].ToString();
}
else
{
return "0";
}
}
//reset the count if needed
public static void resetCount(string siteID)
{
if (onlineList.ContainsKey(siteID))
{
onlineList[siteID] = 0;
}
}}
on my base page i check if there is Session["siteID"]
and if not i start one and make my counter class to add 1 to the site counter:
if (Session["siteID"] == null){
Session["siteID"] = _siteID;
counter.doSiteCountOn(_siteID);}
and finaly on my Session_End i do one count less:
void Session_End(object sender, EventArgs e){
if (Session["siteID"] != null)
{
counter.doSiteCountOff(Session["siteID"].ToString());
}}
thank for your halp
and sorry for my late respons
cheinan