Thanks for clearing my doubt Radim Köhler. Really you saved me. I have been trying to understand this for few days. So I was thinking in the wrong direction, its the debug mode I should understand.
this is the reply you send to me Just before starting to observe any object in the Debug window, call: session.Clear(). From that moment, only stuff already loaded will be available later.
So, in debug window, we should now see some exception about lazy loading failure...
As you said I have added session.Clear() in my code, but I could not find the exception.
where to keep session.Clear()? if possible please edit my code. My code is like
public class EntityUserDetails:IUserDetails
{
private ISession _session;
public EntityUserDetails(ISession session)
{
_session = session;
}
public bool GetUserDetails(string userId,string password)
{
var user = (from userDetails in _session.Query<UserDetails>()
where userDetails.UserId == userId && userDetails.Password == password
select userDetails);
//_session.Clear();
foreach (var get in user)
{
}
return false;
}
}
Did you declare the properties virtual?
Related
I have an ASP.NET Core MVC application that might be restarted from time to time (maintenance); how can make some variable values persistent from an execution to the next?
PS: That's the code that needs to write value as persistent. For example "LastMaintenanceRestartTime = 03/04-2020", the maintenance restart occurs once a day so the code needs to remember the last time it was restarted.
In UWP, I could do the following code but I can't seem to find an equivalent for ASP.NET Core:
Windows.Storage.ApplicationData.Current.LocalSettings.Values[key] = value;
The best I could find is the following code but the values are only persistent within the same execution:
AppDomain.CurrentDomain.SetData(key, value);
Some talk about "Application.Settings" but I can't seem to be able to reach this namespace...
I've also seen some people talking about "AppSettings" files that can be modified during execution but it seems rather complex to keep a simple value persistent...
Do you have any recommendation, solution or ideas for me?
I found the solution:
static void ReadSetting(string key)
{
try
{
var appSettings = ConfigurationManager.AppSettings;
string result = appSettings[key] ?? "Not Found";
Console.WriteLine(result);
}
catch (ConfigurationErrorsException)
{
Console.WriteLine("Error reading app settings");
}
}
static void AddUpdateAppSettings(string key, string value)
{
try
{
var configFile = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
var settings = configFile.AppSettings.Settings;
if (settings[key] == null)
{
settings.Add(key, value);
}
else
{
settings[key].Value = value;
}
configFile.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection(configFile.AppSettings.SectionInformation.Name);
}
catch (ConfigurationErrorsException)
{
Console.WriteLine("Error writing app settings");
}
}
Link: https://learn.microsoft.com/en-us/dotnet/api/system.configuration.configurationmanager.appsettings?redirectedfrom=MSDN&view=dotnet-plat-ext-5.0#System_Configuration_ConfigurationManager_AppSettings
Create a model to save data and last execution time
public class ApplicationData {
public DateTime LastExecutionTime {get;set;}
public string Data {get;set;}
public bool isRunningFirstTime {get;set}
}
1.On first application run, model should be updated to current values and isRunningFirstTime should be set to false.
2. On second run, read or update values based on date and application running count
Expanding on #rashidali answer (and not saying best, but):
public class ApplicationData
{
private DateTime _lastExecutionTime;
public DateTime LastExecutionTime
{
get
{
_lastExecutionTime = (read from file/database);
return _lastExecutionTime;
}
set
{
_lastExecutionTime = value;
(write _lastExecutionTime to file/database);
}
}
public string Data {get;set;}
public bool isRunningFirstTime {get;set}
}
While I have found many instances of this question on SO, none of the solutions I have implemented have solved my problem; hopefully you can help me solve this riddle. Note: This is my first foray into the world of COM objects, so my ignorance is as deep as it is wide.
As a beginning, I am using Adrian Brown's Outlook Add-In code. I won't duplicate his CalendarMonitor class entirely; here are the relevant parts:
public class CalendarMonitor
{
private ItemsEvents_ItemAddEventHandler itemAddEventHandler;
public event EventHandler<EventArgs<AppointmentItem>> AppointmentAdded = delegate { };
public CalendarMonitor(Explorer explorer)
{
_calendarItems = new List<Items>();
HookupDefaultCalendarEvents(session);
}
private void HookupDefaultCalendarEvents(_NameSpace session)
{
var folder = session.GetDefaultFolder(OlDefaultFolders.olFolderCalendar);
if (folder == null) return;
try
{
HookupCalendarEvents(folder);
}
finally
{
Marshal.ReleaseComObject(folder);
folder = null;
}
}
private void HookupCalendarEvents(MAPIFolder calendarFolder)
{
var items = calendarFolder.Items;
_calendarItems.Add(items);
// Add listeners
itemAddEventHandler = new ItemsEvents_ItemAddEventHandler(CalendarItems_ItemAdd);
items.ItemAdd += itemAddEventHandler;
}
private void CalendarItems_ItemAdd(object obj)
{
var appointment = (obj as AppointmentItem);
if (appointment == null) return;
try
{
AppointmentAdded(this, new EventArgs<AppointmentItem>(appointment));
}
finally
{
Marshal.ReleaseComObject(appointment);
appointment = null;
}
}
Bits not relevant to adding appointments have been redacted.
I instantiate the CalendarMonitor class when I spool up the Add-in, and do the work in the AppointmentAdded event, including adding a UserProperty to the AppointmentItem:
private void ThisAddIn_Startup(object sender, EventArgs e)
{
_calendarMonitor = new CalendarMonitor(Application.ActiveExplorer());
_calendarMonitor.AppointmentAdded += monitor_AppointmentAdded;
}
private async void monitor_AppointmentAdded(object sender, EventArgs<AppointmentItem> e)
{
var item = e.Value;
Debug.Print("Outlook Appointment Added: {0}", item.GlobalAppointmentID);
try
{
var result = await GCalUtils.AddEventAsync(item);
//store a reference to the GCal Event for later.
AddUserProperty(item, Resources.GCalId, result.Id);
Debug.Print("GCal Appointment Added: {0}", result.Id);
}
catch (GoogleApiException ex)
{
PrintToDebug(ex);
}
finally
{
Marshal.ReleaseComObject(item);
item = null;
}
}
The error is thrown here, where I try to add a UserProperty to the AppointmentItem. I have followed the best example I could find:
private void AddUserProperty(AppointmentItem item, string propertyName, object value)
{
UserProperties userProperties = null;
UserProperty userProperty = null;
try
{
userProperties = item.UserProperties;
userProperty = userProperties.Add(propertyName, OlUserPropertyType.olText);
userProperty.Value = value;
item.Save();
}
catch (Exception ex)
{
Debug.Print("Error setting User Properties:");
PrintToDebug(ex);
}
finally
{
if (userProperty != null) Marshal.ReleaseComObject(userProperty);
if (userProperties != null) Marshal.ReleaseComObject(userProperties);
userProperty = null;
userProperties = null;
}
}
... but it chokes on when I try to add the UserProperty to the AppointmentItem. I get the ever-popular error: COM object that has been separated from its underlying RCW cannot be used. In all honesty, I have no idea what I'm doing; so I'm desperately seeking a Jedi Master to my Padawan.
The main problem here is using Marshal.ReleaseComObject for RCW's that are used in more than one place by the managed runtime.
In fact, this code provoked the problem. Let's see class CalendarMonitor:
private void CalendarItems_ItemAdd(object obj)
{
var appointment = (obj as AppointmentItem);
if (appointment == null) return;
try
{
AppointmentAdded(this, new EventArgs<AppointmentItem>(appointment));
}
finally
{
Marshal.ReleaseComObject(appointment);
After the event returns, it tells the managed runtime to release the COM object (from the point of view of the whole managed runtime, but no further).
appointment = null;
}
}
Then, an async event is attached, which will actually return before using the appointment, right at the await line:
private async void monitor_AppointmentAdded(object sender, EventArgs<AppointmentItem> e)
{
var item = e.Value;
Debug.Print("Outlook Appointment Added: {0}", item.GlobalAppointmentID);
try
{
var result = await GCalUtils.AddEventAsync(item);
This method actually returns here. C#'s async code generation breaks async methods at await points, generating continuation passing style (CPS) anonymous methods for each block of code that handles an awaited result.
//store a reference to the GCal Event for later.
AddUserProperty(item, Resources.GCalId, result.Id);
Debug.Print("GCal Appointment Added: {0}", result.Id);
}
catch (GoogleApiException ex)
{
PrintToDebug(ex);
}
finally
{
Marshal.ReleaseComObject(item);
Look, it's releasing the COM object again. No problem, but not optimal at all. This is an indicator of not knowing what is going on by using ReleaseComObject, it's better to avoid it unless proven necessary.
item = null;
}
}
In essence the use of ReleaseComObject should be subject to a thorough review of the following points:
Do I need to actually make sure the managed environment releases the object right now instead of at an indeterminate time?
Occasionally, some native objects need to be released to cause relevant side effects.
For instance, under a distributed transaction to make sure the object commits, but if you find the need to do that, then perhaps you're developing a serviced component and you're not enlisting objects in manual transactions properly.
Other times, you're iterating a huge set of objects, no matter how small each object is, and you may need to free them in order to not bring either your application or the remote application down. Sometimes, GC'ing more often, switching to 64-bit and/or adding RAM solves the problem in one way or the other.
Am I the sole owner of/pointer to the object from the managed environment's point of view?
For instance, did I create it, or was the object provided indirectly by another object I created?
Are there no further references to this object or its container in the managed environment?
Am I definitely not using the object after ReleaseComObject, in the code that follows it, or at any other time (e.g. by making sure not to store it in a field, or closure, even in the form of an iterator method or async method)?
This is to avoid the dreaded disconnected RCW exception.
I have a WCF service which has its Thread.CurrentPrincipal set in the ServiceConfiguration.ClaimsAuthorizationManager.
When I implement the service asynchronously like this:
public IAsyncResult BeginMethod1(AsyncCallback callback, object state)
{
// Audit log call (uses Thread.CurrentPrincipal)
var task = Task<int>.Factory.StartNew(this.WorkerFunction, state);
return task.ContinueWith(res => callback(task));
}
public string EndMethod1(IAsyncResult ar)
{
// Audit log result (uses Thread.CurrentPrincipal)
return ar.AsyncState as string;
}
private int WorkerFunction(object state)
{
// perform work
}
I find that the Thread.CurrentPrincipal is set to the correct ClaimsPrincipal in the Begin-method and also in the WorkerFunction, but in the End-method it's set to a GenericPrincipal.
I know I can enable ASP.NET compatibility for the service and use HttpContext.Current.User which has the correct principal in all methods, but I'd rather not do this.
Is there a way to force the Thread.CurrentPrincipal to the correct ClaimsPrincipal without turning on ASP.NET compatibility?
Starting with a summary of WCF extension points, you'll see the one that is expressly designed to solve your problem. It is called a CallContextInitializer. Take a look at this article which gives CallContextInitializer sample code.
If you make an ICallContextInitializer extension, you will be given control over both the BeginXXX thread context AND the EndXXX thread context. You are saying that the ClaimsAuthorizationManager has correctly established the user principal in your BeginXXX(...) method. In that case, you then make for yourself a custom ICallContextInitializer which either assigns or records the CurrentPrincipal, depending on whether it is handling your BeginXXX() or your EndXXX(). Something like:
public object BeforeInvoke(System.ServiceModel.InstanceContext instanceContext, System.ServiceModel.IClientChannel channel, System.ServiceModel.Channels.Message request){
object principal = null;
if (request.Properties.TryGetValue("userPrincipal", out principal))
{
//If we got here, it means we're about to call the EndXXX(...) method.
Thread.CurrentPrincipal = (IPrincipal)principal;
}
else
{
//If we got here, it means we're about to call the BeginXXX(...) method.
request.Properties["userPrincipal"] = Thread.CurrentPrincipal;
}
...
}
To clarify further, consider two cases. Suppose you implemented both an ICallContextInitializer and an IParameterInspector. Suppose that these hooks are expected to execute with a synchronous WCF service and with an async WCF service (which is your special case).
Below are the sequence of events and the explanation of what is happening:
Synchronous Case
ICallContextInitializer.BeforeInvoke();
IParemeterInspector.BeforeCall();
//...service executes...
IParameterInspector.AfterCall();
ICallContextInitializer.AfterInvoke();
Nothing surprising in the above code. But now look below at what happens with asynchronous service operations...
Asynchronous Case
ICallContextInitializer.BeforeInvoke(); //TryGetValue() fails, so this records the UserPrincipal.
IParameterInspector.BeforeCall();
//...Your BeginXXX() routine now executes...
ICallContextInitializer.AfterInvoke();
//...Now your Task async code executes (or finishes executing)...
ICallContextInitializercut.BeforeInvoke(); //TryGetValue succeeds, so this assigns the UserPrincipal.
//...Your EndXXX() routine now executes...
IParameterInspector.AfterCall();
ICallContextInitializer.AfterInvoke();
As you can see, the CallContextInitializer ensures you have opportunity to initialize values such as your CurrentPrincipal just before the EndXXX() routine runs. It therefore doesn't matter that the EndXXX() routine assuredly is executing on a different thread than did the BeginXXX() routine. And yes, the System.ServiceModel.Channels.Message object which is storing your user principal between Begin/End methods, is preserved and properly transmitted by WCF even though the thread changed.
Overall, this approach allows your EndXXX(IAsyncresult) to execute with the correct IPrincipal, without having to explicitly re-establish the CurrentPrincipal in the EndXXX() routine. And as with any WCF behavior, you can decide if this applies to individual operations, all operations on a contract, or all operations on an endpoint.
Not really the answer to my question, but an alternate approach of implementing the WCF service (in .NET 4.5) that does not exhibit the same issues with Thread.CurrentPrincipal.
public async Task<string> Method1()
{
// Audit log call (uses Thread.CurrentPrincipal)
try
{
return await Task.Factory.StartNew(() => this.WorkerFunction());
}
finally
{
// Audit log result (uses Thread.CurrentPrincipal)
}
}
private string WorkerFunction()
{
// perform work
return string.Empty;
}
The valid approach to this is to create an extension:
public class SLOperationContext : IExtension<OperationContext>
{
private readonly IDictionary<string, object> items;
private static ReaderWriterLockSlim _instanceLock = new ReaderWriterLockSlim();
private SLOperationContext()
{
items = new Dictionary<string, object>();
}
public IDictionary<string, object> Items
{
get { return items; }
}
public static SLOperationContext Current
{
get
{
SLOperationContext context = OperationContext.Current.Extensions.Find<SLOperationContext>();
if (context == null)
{
_instanceLock.EnterWriteLock();
context = new SLOperationContext();
OperationContext.Current.Extensions.Add(context);
_instanceLock.ExitWriteLock();
}
return context;
}
}
public void Attach(OperationContext owner) { }
public void Detach(OperationContext owner) { }
}
Now this extension is used as a container for objects that you want to persist between thread switching as OperationContext.Current will remain the same.
Now you can use this in BeginMethod1 to save current user:
SLOperationContext.Current.Items["Principal"] = OperationContext.Current.ClaimsPrincipal;
And then in EndMethod1 you can get the user by typing:
ClaimsPrincipal principal = SLOperationContext.Current.Items["Principal"];
EDIT (Another approach):
public IAsyncResult BeginMethod1(AsyncCallback callback, object state)
{
var task = Task.Factory.StartNew(this.WorkerFunction, state);
var ec = ExecutionContext.Capture();
return task.ContinueWith(res =>
ExecutionContext.Run(ec, (_) => callback(task), null));
}
well my problem is:
I have a method like:
class Manager
{
void method1()
{
// save object in database to get ID
int newId = this.Repository.Save(obj);
try {
// call remote webservice to save another object with same ID as in local DB
webservice.Save(remoteObj, id);
}
catch(Exception e)
{
// do Rollback in Repository here
}
}
}
Bassically this is the code. Repository use NHibernate to save to DB. I need to save in DB to know the new ID and then send this ID to webservice. If something fail calling webservice I want to rollback and discard saved object.... and here is my problem. I can't open and control a transaction in Repository from my class Manager.
I already try with this also:
class Manager
{
void method1()
{
using (TransactionScope scope = new TransactionScope())
{
// save object in database to get ID
int newId = this.Repository.Save(obj);
// call remote webservice to save another object with same ID
// as in local DB
webservice.Save(remoteObj, id);
scope.Complete();
}
}
}
Here the problem is that the rollback is OK but not the Save(Create in NHibernate). I get error about that object "Transaction" is not found or the transaction is already closed just after the line : "scope.Complete();".
I think that something is wrong trying to control NHibernate transaction with TransactionScope .
I dont know if is a problem about approach, maybe another way should be used to handle this situation... ??
any help or idea where to find ??
Thanks a lot !!
Assuming you already have an opened session in a CurrentSession property/variable and that you could pass that working session to your repository, I would do the following:
using(var trx = CurrentSession.BeginTransaction())
{
try
{
int newId = this.Repository.Save(obj, CurrentSession);
webservice.Save(remoteObj, id);
trx.Commit();
}
catch
{
trx.Rollback();
}
}
I've tried following the steps in Joost Van Schaik's article on tombstoning but was unable to get it to work for me. I'm no doubt doing something wrong. In my ViewModel:
private string _foobar ="init";
public string testStr
{
get
{
return _foobar;
}
set
{
_foobar = value;
}
}
And in my page:
<TextBox x:Name="tBoxTest" Text="{Binding testStr, Mode=TwoWay}" />
While the application is running, changing the value in tBoxTest sets _foobar just fine, but try to serialize it and it’s as if it has forgotten the instance??? Any help would be greatly appreciated.
I was able to get tombstoning to work, along with having an object be visible to all my ViewModels, by doing the following:
In a Model class, I added:
private static Model1 _instance;
public static Model1 Instance
{
get { return _instance; }
set { _instance = value; }
}
public static void CreateNew()
{
if (_instance == null)
{
_instance = new Model1();
_instance.FirstString = "init";
}
}
Then in ApplicationExtensions.cs I added:
public static void SaveToIsolatedStorage(this Application app, Model1 model)
{
var dataFileName = GetIsFile((model.GetType()));
using (var userAppStore =
IsolatedStorageFile.GetUserStoreForApplication())
{
if (userAppStore.FileExists(dataFileName))
{
userAppStore.DeleteFile(dataFileName);
}
using (var iss = userAppStore.CreateFile(dataFileName))
{
SilverlightSerializer.Serialize(model, iss);
}
}
}
And in App.xaml.cs I changed LoadModel() to:
private void LoadModel()
{
try
{
Model1.Instance = this.RetrieveFromIsolatedStorage<Model1>();
}
catch (Exception) { }
if (Model1.Instance == null) Model1.CreateNew();
}
That all made things like this work in my ViewModel files:
public string TestStr
{
get
{
return Model1.Instance.FirstString;
}
set
{
Model1.Instance.FirstString = value;
}
}
And by that, I mean that the Model1 object is getting serialized and tombstoning is working - at least I’m getting what I think I want. I’ve tested it a lot by navigating between apps, phone settings, turning the phone off and on, locking it and calling it while in the app from another phone. Performance when deserializing is great. And I can work with the vars.
That said, Mr. Van Schaik replied to a request for assistance with: "If you are subclassing from an MVVMLight ViewModelBase it does, and then you should call RaisePropertyChanged from your setter like this:
private string _foobar ="init";
public string TestStr
{
get
{
return _foobar;
}
set
{
RaisePropertyChanged("TestStr");
_foobar = value;
}
}
RaisePropertyChanged notifies any listenings views (i.e. the TextBox you bound to it) that a property is changed and that the should update their contents. This is a crucial mechanism."
So I will work with what I was originally trying but with the addition of RaisePropertyChanged to see what that does.
UPDATE
Although I implemented RaisedPropertyChanged (using the code snippet mvvminpc) in my MainViewModel.cs file, that still had no effect (as good as it may be for other things) on serializing anything created within the ViewModel. I'm probably still doing something wrong, but it may also be because view models inherit from a protected class (answer from Laurent Bugnion). I (very reluctantly) tried changing that class from protected to public and recompiling, but it didn't help in my case and I hate to fork a referenced library like that. Anyway, I'm just forging ahead for now with creating the Model1 instance in App.xaml.cs. Seems to work. While I was at it, I modified one of Van Schaik's methods to accept any type of object:
public static void SaveToIsolatedStorage<T>(this Application app, T obj)
where T : class
{
var dataFileName = GetIsFile(typeof(T));
using (var userAppStore =
IsolatedStorageFile.GetUserStoreForApplication())
{
if (userAppStore.FileExists(dataFileName))
{
userAppStore.DeleteFile(dataFileName);
}
using (var iss = userAppStore.CreateFile(dataFileName))
{
SilverlightSerializer.Serialize(obj, iss);
}
}
}
From the code you've posted there isn't an instant answer.
My advice to debug this is:
if you've copied the code exactly from that article then add something (a messagebox?) to the empty catch handler - `catch (Exception){ }
use the debugger to put breakpoints in the LoadModel and SaveToIsolatedStorage methods
use these breakpoints to step through the Load and Save code - is the code correctly loading and saving?
To be honest, with problems like this, doing a little investigation yourself is much better than asking questions on here (IMO!)