The following is how I usually handle objects in Session State, I have a const string as the session name and then have a property with a get and set for the Object.
What I was wondering was if the 'Session.Remove()' call was necessary (to keep things clean and tidy) and if there was significant overhead and doing this removal.
I have the Session.Remove there basically because it makes me feel better (OCD i know), and makes me feel like the session is cleaner, but I would like to know if it isn't needed.
private const string sesMyObject = "{C2CC72C3-1466-42D4-8579-CAA11F261D55}";
public MyObject MyObjectProperty
{
get
{
return Session[sesMyObject] as MyObject;
}
set
{
Session.Remove(sesMyObject);
Session.Add(sesMyObject, value);
}
}
EDIT
per the answers below i have changed my properties to the following:
private const string sesMyObject = "{C2CC72C3-1466-42D4-8579-CAA11F261D55}";
public MyObject MyObjectProperty
{
get
{
return Session[sesMyObject] as MyObject;
}
set
{
Session[sesMyObject] = value;
}
}
thanks!
If you really want to be safe, try converting the object to a IDisposable, and if it succeeds, call Dispose.
IDisposable sesDispObj = Session[sesMyObject] as IDisposable;
if (sesDispObj != null)
sesDispObj.Dispose();
Other than that,
Session[sesMyObject] = value
is pretty much the same as
Session.Remove(sesMyObject);
Session.Add(sesMyObject, value);
It's overkill. Refering MSDN
If the name parameter refers to an
existing session state item, the
existing item is overwritten with the
specified value.
Session[sesMyObject] = value;
is shorter, simpler to read, and should have slightly better performance, but unless this code is being repeated very many times in succession, it shouldn't make a difference.
Related
I am trying to store the result of the api call that returns results of type IEnumerable to a viewstate in my asp.net application. After executing line
this.PendingApprovalUserChangeRequest = pendingChangeRequest , i see the value null in this.PendingApprovalUserChangeRequest though the pendingChangeRequest contains value
What could be the problem ?
protected IEnumerable<PendingApprovalUserChangeRequest> PendingApprovalUserChangeRequest
{
get
{
if (ViewState["UserChangeRequestsDataTable"] != null)
{
return (IEnumerable<PendingApprovalUserChangeRequest>)ViewState["PendingApprovalUserChangeRequest"];
}
else
{
return null;
}
}
set { ViewState["PendingApprovalUserChangeRequest"] = value; }
}
var pendingChangeRequest = Task.Run(async () => await service.GetPendingChangeRequest()).Result;
this.PendingApprovalUserChangeRequest = pendingChangeRequest;
Albeit the real core problem is using ASP.NET Web Forms at all, your next underlying problem is using ViewState in your getter/setter implementations.
That is too much responsibility for a class property, and hides implementation magic from users of PendingApprovalUserChangeRequest property in the future.
What if another developer wants to use PendingApprovalUserChangeRequest property but not in an ASP.NET context and ViewState does not exist?
Simply declare your property for your class:
protected IEnumerable<string> PendingApprovalUserChangeRequest { get; set; }
Then use ViewState in the Service/Controller/Manager.:
var result = Task.Run(async () => await service.GetPendingChangeRequest()).Result;
MyClass.PendingApprovalUserChangeRequest = result; //examples setting the property
ViewState["PendingApprovalUserChangeRequest"] = result; //if you need to store the result for View to use
DisplayUserChangeRequestsData(result); //call the function you mentioned in your comments
This way you do not have to deal with the confusion of your getter/setter for hydrating/populating your ViewState key "PendingApprovalUserChangeRequest".
This concept of an instance of a class persisting its own properties beyond its own instantiation in memory is an anti-pattern and you should be thinking about other components/mechanisms persisting the state of your class that contains the property "PendingApprovalUserChangeRequest". Why wouldn't you persist an instance of the class? Either way, a property worrying about its own persistence via ViewState or some other pattern is definitely a bad idea, buggy, confusing and wrought with design flaws and headaches.
can someone please explain me the code written below
public IList<GetProductPrice> CurrentPage
{
get { return ViewState["CurrentPage"] as List<GetProductPrice>; }
set { ViewState["CurrentPage"] = value; }
}
It is called a Property. They generate a getter and setter functions when compiled:
List<GetProductPrice> GetCurrentPage(){
return ViewState["CurrentPage"] as List<GetProductPrice>;
}
void SetCurrentPage(List<GetProductPrice> value) {
ViewState["CurrentPage"] = value;
}
//i think its actual get_.. but it doesn't matter for the example
So its generates ease of use getter setters. which you can just call by using:
var test = CurrentPage; //compiled to var test = GetCurrenctPage();
CurrentPage = test; //compiled to SetCurrentPage(test);
If you leave the getter and setter empty like this:
public int CurrentPage
{
get;
set;
}
it will also generate a backing field on the class where it stores the data:
private int _currentPage;
public GetCurrentPage(){ return _currentPage }
public SetCurrentPage(int value) { _currentPage = value }
Why do we do this?
Using getters and setters is a very old best practise from java (where ide's would have an option to generate them). But this would lead to a lot of boilerplate code!
In C# they try to counter this by adding these properties. But why do we need getters and setters? For example if you want to be notified when a value changes (to mark the classes it self as dirty). I think entity framework uses it to track if a model is changed otherwise it wont do a db update call. There are also other usefull tools that inject code in properties on compile time. to add extra functionality.
How not to use it:
using properties to return HttpContext.Current Is a dangerous one because you secretly depend on the HttpContext so try not to do this at any time!
Generally its also bad practise to use it when the code inside the get or set is very heavy (very instensive). Its bad practise because someone else using the code might think he is just setting a property/field while actually some very heavy code is executed. its best practice to make a special function for this instead and private the getter/setter:
public int Property {get; private set; }
public SetProperty(int value){
//intensive code here:
Property = value;
}
This property is letting the consumer of the property to use it like Local collection without referring the ViewState in the code. It will make the code simple and easy to use.
get { return ViewState["CurrentPage"] as List<GetProductPrice>; }
Here the ViewState object ViewState["CurrentPage"] is converted to list of GetProductPrice
set { ViewState["CurrentPage"] = value; }
Here the List is assigned to ViewState["CurrentPage"]
This code will only work in a controller, where ViewState is a property. This CurrentPage property provides a statically-typed way to access a certain ViewState item through that property.
So instead of sprinkling ViewState["CurrentPage"] as List<GetProductPrice> all over your controller code where you want to access the "current page", you can now simply use the CurrentPage property.
Of course "current page" is a term made up by the developer who chose to name things like this, I don't see how a List<GetProductPrice> has a relation to the "current page".
I have a method where I READ objects from DB, for instance:
public Object getProduct(int categoryId, int productId)
{
DataClassesDataContext db = new DataClassesDataContext(Settings.getDefaultConnectionStringName());
switch (categoryId)
{
case CCategorii.CARTI_ID:
{
IEnumerable<Carti> product = (from c in db.Cartis
where c.Carti_id == productId
&& c.Vizibil == true
select c);
if (product.Count() != 0)
return product.First();
break;
}
//so on
}
}
Now I have another method where I do the update:
public void updateProduct()
{
Object productToBeUpdated = getProduct(1,1);
DataClassesDataContext db = new DataClassesDataContext(Settings.getDefaultConnectionStringName());
//update some properties of the product
productToBeUpdated.setQuantity(productToBeUpdated.getQuantity()+1);
db.submitChanges();
}
Well, the product was succcesfully read from previous method but changes were not done into the DB.
I think the cause is that I do this READ-UPDATE in two different DataContext...If this is the cause how do you threat this situations?
Oh yeah, I can read the product and update in the same method but this means to duplicate the method I use for reading and add to it update stuff... and I would like to avoid this.
I would assume it's because you are using a different context for the read and write. Try moving your DataClassesDataContext variable to class level.
One option is: use a common data context, and pass it to your getXXX methods as a parameter:
public Object getProduct(DataClassesDataContext db, int categoryId, int productId)
{
switch (categoryId)
{
case CCategorii.CARTI_ID:
{
IEnumerable<Carti> product = (from c in db.Cartis
where c.Carti_id == productId
&& c.Vizibil == true
select c);
if (product.Count() != 0)
return product.First();
break;
}
//so on
}
}
and then:
public void updateProduct()
{
using (DataClassesDataContext db = new DataClassesDataContext(Settings.getDefaultConnectionStringName()))
{
Object productToBeUpdated = getProduct(db, 1,1);
//update some properties of the product
productToBeUpdated.setQuantity(productToBeUpdated.getQuantity()+1); // THX #AVD, didn't notice that.
db.submitChanges();
}
}
You are using two different instances of your DataContext.
When implementing a web app, the best option is usually to align the lifetime of your DataContext to the lifetime of one http request. The lifetime you use is just too short.
Another option is to attach the object to the write DataContext:
db.Cartis.Attach(yourReadObject);
updateProperties(yourReadObject);
db.submitChanges();
EDIT
Ok, you have to detach the object from your other context first. See this article on how to do it.
But i really would recommend to use a single DataContext object and extend the lifetime to the httprequest scope.
This can be done really nice with an ioc container like autofac.
You can't use ++ operator and use the same context to update an object. Try this,
productToBeUpdated.setQuantity(productToBeUpdated.getQuantity()+1);
As soon as your DataContext goes out of scope your entity becomes detached from it. That means it's no longer being tracked by your Context and it can't save the changes you make to it.
You could share the context so the entity doesn't get detached from your context or you could reattach it to the second context (DataContext.Attach)
I've created my own cache manager for a web site I'm developing and I was looking to find the best way to clear the cache under certain circumstances.
I found many articles saying the proper way to clear the cache is to call HttpRuntime.Close()
However, in my unit tests setup I call the encapsulated function HttpRuntime.Close() and the cache is NOT being cleared out.
I expected it to perform something similar to
foreach (DictionaryEntry cacheItem in HttpRuntime.Cache)
{
HttpRuntime.Cache.Remove(cacheItem.Key.ToString());
}
The foreach loop works great in my encapsulated function, but the Close() never works right.
Am I misunderstanding the purpose of HttpRuntime.Close() or is there something more sinister going on here?
Don't use Close, it does more than the docs say. And the docs also say not to use it while processing normal requests...
This is the reflected source of Close():
[SecurityPermission(SecurityAction.Demand, Unrestricted=true)]
public static void Close() {
if (_theRuntime.InitiateShutdownOnce()) {
SetShutdownReason(ApplicationShutdownReason.HttpRuntimeClose, "HttpRuntime.Close is called");
if (HostingEnvironment.IsHosted) {
HostingEnvironment.InitiateShutdown();
} else {
_theRuntime.Dispose();
}
}
}
Also, you cannot iterate over a collection and remove items from it at the same time, as this renders the enumeration invalid.
So, try this instead, which doesn't change what it loops over:
List<string> toRemove = new List<string>();
foreach (DictionaryEntry cacheItem in HttpRuntime.Cache) {
toRemove.Add(cacheItem.Key.ToString());
}
foreach (string key in toRemove) {
HttpRuntime.Cache.Remove(key);
}
That being said, really, you should try to use cache dependencies to have the invalid cache entries cleared automatically for you, and then all this becomes unnecessary.
I understand the issue with enumeration but for some reason the Cache doesn't seem to have a problem removing an item while walking through the list.
If you drill down to the detail implementation, you will find the Enumerator is created by CacheSingle.CreateEnumerator, a new Hashtable instance is created for enumeration.
That's why you can do the remove in a foreach loop.
you could simply implement your own Cache class, check the below one:
public sealed class YourCache<T>
{
private Dictionary<string, T> _dictionary = new Dictionary<string, T>();
private YourCache()
{
}
public static YourCache<T> Current
{
get
{
string key = "YourCache|" + typeof(T).FullName;
YourCache<T> current = HttpContext.Current.Cache[key] as YourCache<T>;
if (current == null)
{
current = new YourCache<T>();
HttpContext.Current.Cache[key] = current;
}
return current;
}
}
public T Get(string key, T defaultValue)
{
if (string.IsNullOrWhiteSpace(key))
throw new ArgumentNullException("key should not be NULL");
T value;
if (_dictionary.TryGetValue(key, out value))
return value;
return defaultValue;
}
public void Set(string key, T value)
{
if (key == null)
throw new ArgumentNullException("key");
_dictionary[key] = value;
}
public void Clear()
{
_dictionary.Clear();
}
}
you could call items from cache or even clear them using the following:
// put something in this intermediate cache
YourCache<ClassObject>.Current.Set("myKey", myObj);
// clear this cache
YourCache<ClassObject>.Current.Clear();
I have a linq query and I am trying to put that in to a serializable object for a distributed caching (Velocity) but its failing due to a LINQ-to-SQL lazy list
like so
return from b in _datacontext.MemberBlogs
let cats = GetBlogCategories(b.MemberBlogID)
select new MemberBlogs
{
MemberBlogID = b.MemberBlogID,
MemberID = b.MemberID,
BlogTitle = b.BlogTitle,
BlogURL = b.BlogURL,
BlogUsername = b.BlogUsername,
BlogPassword = b.BlogPassword,
Categories = new LazyList<MemberBlogCategories>(cats)
};
LazyList is the same class Rob Conery uses in his MVC storefront...
all three classes are marked serializable (MemberBlogs,MemberBlogCategories,LazyList... any ideas?
If you are putting it in a distributed cache you will need to avoid the LazyList altogether. You can then call .ToList() around the whole LINQ statement as in:
(from x select new MemberBlogs).ToList()
This should then be cachable because it forces the queries to be evaluated.
I'm just guessing, but I'd say the problem is that it is serializing the query instead of the results; I don't know what the implementation of the LazyList looks like, but you can probably add an OnSerializing method that actually executes the query prior to serializing it; Something like:
[OnSerializing]
private void ExecuteLinqQuery(StreamingContext context)
{
if (!SomethingThatIndicatesThisLinqQueryHasNotBeenExecuted)
LinqVariable.ToList()
}
This way you get to keep the Lazy Load (for anything that doesn't go into your cache), but then also if it does hit the cache, it'll execute the linq query and cache the results.
If you're caching it why are you using a lazy list? Don't use a lazy list, use caching, and the problem goes away.
I know this is an old post but I had the same issue as I wanted to execute my LazyList and put them into the AppFabric Cache. I ended up putting some custom serialization logic into the LazyList type.
The first part now looks like this:
public class LazyList<T> : IList<T>, ISerializable
{
public LazyList()
{
this.query = new List<T>().AsQueryable();
}
public LazyList(SerializationInfo info, StreamingContext context)
{
try {
this.inner = (List<T>)info.GetValue("InnerList", typeof(List<T>));
}
catch (Exception ex)
{
this.inner = null;
}
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
if (this.inner != null)
info.AddValue("InnerList", this.inner.ToList());
}
public LazyList(IQueryable<T> query)
{
this.query = query;
}
public LazyList(List<T> l)
{
inner = l;
}
}