Session.Remove("session_variable"); not working? - c#

Hi in the following stuff am trying to remove the session after completing the certain tasks. but the session.remove() not working here.
if (Session["CaseNumber"] != "" || Session["CaseNumber"] != null)
{
casenumber = Session["CaseNumber"].ToString();
guid = Session["guid"].ToString();
_duration = bal.viewServiceActivity(guid);
case1 = bal.viewCaseDetail(casenumber);
dt = bal.getRelatedNotes(guid);
Session.Remove("CaseNumber");
Session.Remove("guid");
}
else
{
casenumber = Session["searchCase"].ToString();
guid = Session["caseGuid"].ToString();
_duration = bal.viewServiceActivity(guid);
case1 = bal.viewCaseDetail(casenumber);
dt = bal.getRelatedNotes(guid);
Session.Remove("searchCase");
Session.Remove("caseGuid");
}

There's nothing really wrong with portion of your code shown above. Just understanding is required about how it works.
Session.Remove(key) removes memory used for the key in the session dictionary. When using second approach of : Session["searchCase"]=null; , the key will still exist in the Session although the value is null.
Try setting the Session["Key_Name"] to null. For example:
if (Session["CaseNumber"] != "" || Session["CaseNumber"] != null)
{
casenumber = Session["CaseNumber"].ToString();
guid = Session["guid"].ToString();
_duration = bal.viewServiceActivity(guid);
case1 = bal.viewCaseDetail(casenumber);
dt = bal.getRelatedNotes(guid);
Session["CaseNumber"] = null; // Set NULL
Session["guid"] = null; // Set NULL
}
Session.Remove() doesn't destroys the object bypassing all basic .net rules of object referencing and memory management. What you need to understand here is that Session.Remove() does exactly what it suggests: It removes the reference to the object from its internal collection. Nothing more to expect.
If you need something destroyed, you need to implement IDisposable, and furthermore, you may instruct the garbage collector to collect if you are in a hurry using GC.Collect().
Check this SO question: Proper use of the IDisposable interface
Microsoft Forum confirms the same.
It seems more like an optimization OR so called standard way of implementation.
When you remove an object it is 'marked for removal' but not really removed...unless space is required.
It's how garbage collection works. Just because an object goes out of scope doesn't mean it's destructor gets called and the memory freed immediately. May be GC can remove an object much later.
Still, as a last check, do this :
Make sure you are not viewing a cached version of the page, or you don't add the item to the Session object again somewhere in your application.

Related

Roslyn Check If Field Declaration has been assigned to

I'm writing an app which converts keys to use resources from a RESX File. This code was working with local variables before:
public static void AnalyzeConstDeclaration(SyntaxNodeAnalysisContext context)
{
var fieldDeclaration = (FieldDeclarationSyntax)context.Node;
if (false == IsValidFieldDeclaration(context, fieldDeclaration))
{
return;
}
var firstVariable = fieldDeclaration.Declaration.Variables.FirstOrDefault();
var dataFlowAnalysis = context.SemanticModel.AnalyzeDataFlow(firstVariable);
var variableSymbol = context.SemanticModel.GetDeclaredSymbol(firstVariable);
if (dataFlowAnalysis.WrittenOutside.Contains(variableSymbol))
{
return;
}
var firstSymbol = context.SemanticModel.GetDeclaredSymbol(firstVariable);
context.ReportDiagnostic(Diagnostic.Create(Rule, context.Node.GetLocation(), firstSymbol.Name));
}
However when I try to get the dataFlowAnalysis I receive an error:
Additional information: statementOrExpression is not a StatementSyntax or an ExpressionSyntax.
How can Ideally just need to see if anyone has written to this variable outside of the declaration.
DataFlow works by analyzing order of execution within a single method.
It doesn't make sense for class-level fields.
Instead, you should use a simple syntax visitor (or SymbolFinder) to search the entire class for assignments to the field.
You'll probably also want to check whether it's ever passed as a ref parameter.

How to evaluate local variable/ parameter state with Roslyn

I have a bit of complicated situation. I must create analyzers/ code fix providers for situations such as a parameter is only assigned but never used or local variable are never used.
For the parameter situation, I'm going for the method declaration and looking at the parameter list to get all the analyzer. I'm going through assignment expressions within the method and I filter the parameters that were assigned with an helper method.
Where it gets fuzzy is I have no clue or to know when a local variable/parameter is used or not. I've gone through symbols but they can't tell me that variable used/ not used. I could try to find how many times a variable's name was mentioned inside a method by turning the method declaration syntax context in a string and look for the parameters that were assigned but that's simply such a BAD idea.
I'm really stuck and I would some help for this from anyone who had previous experience with this kind of situation.
For people who might ask, I'm mostly looking for the missing logic for the analyzer. I have no idea how the code fix provider will work. If you have an idea of what I could do, feel free to include it in your answer ! As of now, I was thinking that a local variable that's not used could be deleted from a method and the same could go for an unused parameter. I'm not sure at the moment.
UPDATE
I'm now trying to use the DataFlow API but it's not working for me at the moment. The oldest answer of this thread gave me a starting point but it's actually not working.
I came up with my own way :
private static bool IsLocalVariableBeingUsed(VariableDeclaratorSyntax variableDeclarator, SyntaxNodeAnalysisContext syntaxNode)
{
var model = syntaxNode.SemanticModel.Compilation.GetSemanticModel(variableDeclarator.SyntaxTree);
var methodBody = variableDeclarator.AncestorsAndSelf(false).OfType<MethodDeclarationSyntax>().First();
var lastMethodNode = methodBody?.ChildNodes().LastOrDefault();
if (lastMethodNode == null)
return false;
var readWrite = syntaxNode.SemanticModel.AnalyzeDataFlow(variableDeclarator, lastMethodNode);
}
But this also is not working. When using a test with NUnit :
var input = #"
class TestClass {
void TestMethod ()
{
int i;
}
}";
I get the following message when the runtime gets to either readWrite or result(from oldest answer):
System.ArgumentOutRangeException Index was out of range Must be non negative and lesser than the size of the collection"
But before that in my analyzer, when I try to validate my node to make sure it's not null and create the appropriate elements for the data flow API, there's no code break (not sure if that is the appropriate term) but at the moment I cannot progress.
You can see whether or not most variable are used (read/written) via the DataFlowAnalysis APIs. I've written an introduction to this API on my blog.
I believe in your case, you're looking for variables that are never read.
var tree = CSharpSyntaxTree.ParseText(#"
public class Sample
{
public void Foo()
{
int unused = 0;
int used = 1;
System.Console.Write(used);
}
}");
var Mscorlib = PortableExecutableReference.CreateFromAssembly(typeof(object).Assembly);
var compilation = CSharpCompilation.Create("MyCompilation",
syntaxTrees: new[] { tree }, references: new[] { Mscorlib });
var model = compilation.GetSemanticModel(tree);
var methodBody = tree.GetRoot().DescendantNodes().OfType<MethodDeclarationSyntax>().Single().Body;
DataFlowAnalysis result = model.AnalyzeDataFlow(methodBody);
var variablesDeclared = result.VariablesDeclared;
var variablesRead = result.ReadInside.Union(result.ReadOutside);
var unused = variablesDeclared.Except(variablesRead);
foreach(var variable in unused)
{
Console.WriteLine(variable);
}
Building on JoshVarty's answer, to get this to work in a diagnostic, I would register a SyntaxNodeAction for all MethodDeclaration Syntax Kinds and then look inside the body for unused variables:
public override void Initialize(AnalysisContext context)
{
context.RegisterSyntaxNodeAction(AnalyzeIt, SyntaxKind.MethodDeclaration);
}
private static void AnalyzeIt(SyntaxNodeAnalysisContext context)
{
var method = context.Node as MethodDeclarationSyntax;
var dataFlow = context.SemanticModel.AnalyzeDataFlow(method.Body);
var variablesDeclared = dataFlow.VariablesDeclared;
var variablesRead = dataFlow.ReadInside.Union(dataFlow.ReadOutside);
var unused = variablesDeclared.Except(variablesRead);
if (unused.Any())
{
foreach (var unusedVar in unused)
{
context.ReportDiagnostic(Diagnostic.Create(Rule, unusedVar.Locations.First()));
}
}
}

Running out of memory looping through mail items

Hi I have a Outlook com addin that is doing some simple searching tricks for me. I am part way through putting it together but I am having issues with it running out of memory. The process is very simple and basically loops through an outlook folder checking each mailItem for a match. given the loop reinitialize the variables each time I would have expected the garbage collector to keep up but when I watch the memory it loses ~10m/sec until the system is out of memory and I get unhandled exceptions.
This is part of the code
private void FindInFolder(Outlook.MAPIFolder FolderToSearch)
{
Outlook.MailItem mailItem;
Outlook.MAPIFolder ParentFolder;
int counter = 0;
StatusBar.Text = "Searching in Folder " + FolderToSearch.FolderPath + "/" + FolderToSearch.Name;
StatusBar.Update();
this.Update();
foreach (COMObject item in FolderToSearch.Items)
{
counter++;
if (counter % 100 == 0)
{
StatusBar.Text = FolderToSearch.FolderPath + "/" + FolderToSearch.Name + " item " + counter + " of " + FolderToSearch.Items.Count;
StatusBar.Update();
if (counter % 1000 == 0)
{
GC.Collect();
}
}
if (item is Outlook.MailItem)
{
mailItem = item as Outlook.MailItem;
if (IsMatch(mailItem))
{
if (mailItem.Parent is Outlook.MAPIFolder)
{
ParentFolder = mailItem.Parent as Outlook.MAPIFolder;
ResultGrd.Rows.Add(mailItem.EntryID, ParentFolder.FolderPath, mailItem.SenderName, mailItem.Subject, mailItem.SentOn);
}
}
}
mailItem = null;
}
}
Which calls
private Boolean IsMatch(Outlook.MailItem inItem)
{
Boolean subBool = false;
Boolean NameBool = false;
try
{
if (null != inItem)
{
if (SubjectTxt.Text != "")
{
if (inItem.Subject.Contains(SubjectTxt.Text))
{
subBool = true;
}
}
else
{
subBool = true;
}
if (NameTxt.Text != "")
{
if (inItem.Sender != null)
{
if (inItem.Sender.Name.Contains(NameTxt.Text))
{
NameBool = true;
}
}
}
else
{
NameBool = true;
}
return subBool && NameBool;
}
}
catch (System.Runtime.InteropServices.COMException ce)
{
if (ce.ErrorCode == -2147467259)
{
//DO nothing just move to the next one
}
else
{
MessageBox.Show("Crash in IsMatch error code = " + ce.ErrorCode + " " + ce.InnerException);
}
}
return false;
}
Please excuse all the error catching part at the bottom and the GC.collect they are some of my attempts to work out what is wrong and free up memory.
Note also FindInFolder is called by a new thread so I can interact with results while it continues to search.
What I have tried so far:
Making variables local to function not class so the are retrievable by G, however the most used variable in 'item' as it is part of foreach it must be declared that way.
every 1000 mailItems do a manual GC, this made no difference at all.
For some reason it needs alot of memory just looping through the items and GC never frees them up.
Please also note I am using netoffice not VSTO for Com addin.
First of it all: This is NetOffice code and you dont need Marshal.ReleaseComObject in NetOffice. (Moreover, its useless to call ReleaseComObject here) Use Dispose() for the instance instead.
Keep in your mind: NetOffice handle COM proxies for you (Thats why its allowed to use two 2 dots in NetOffice).
In your case its internaly stored as:
// FolderToSearch
-- Items
--Enumerator
-- Item
-- Item
-- ....
Use item.Dispose() at the end of each loop to remove/free the item instance or use the following after foreach
FolderToSearch.Dipose()
// dispose folder instance and all proxies there comes from
FolderToSearch.DisposeChildInstances()
// dispose all proxies there comes from but keep the folder instance alive
Next:
The Items enumerator here is a custom enumerator(given by NetOffice)
However it works fine with small amount of items but dont do this in a more
heavier scenario(may exchange server and thousands of items). The local workstation/program can't handle this in memory. For this reason Microsoft provides only the well kown GetFirst/GetNext pattern. In NetOffice it looks like:
Outlook._Items items = FolderToSearch.Items;
COMObject item = null;
do
{
if (null == item)
item = items.GetFirst() as COMObject;
if (null == item)
break;
// do what you want here
item.Dispose();
item = items.GetNext() as COMObject;
} while (null != item);
This should works as well.
When working with COM objects from C#, there were 2 tricks that I used to prevent memory and COM object reference counts from building:
Use System.Runtime.InteropServices.Marshal.ReleaseComObject() to release COM objects as you are done with them. This forces a COM "release" on the object.
Do not foreach to iterate through a COM collection. foreach holds on to an enumerator object, which prevents other objects from being released.
So, instead of this:
foreach (COMObject item in FolderToSearch.Items)
{
// ....
}
do this:
Items items = FolderToSearch.Items;
try
{
for (int i = 0; i < items.Count; ++i)
{
COMObject item = items[i];
try
{
// work
}
finally
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(item);
}
}
}
finally
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(items);
}
These tips helped me reduce memory and object consumption.
Disclaimer: I cannot attest to whether this is good practice or not though.
First, I'd recommend using the Find/FindNext or Restrict methods of the Items class instead of iterating through all items in the folder. For example:
Sub DemoFindNext()
Dim myNameSpace As Outlook.NameSpace
Dim tdystart As Date
Dim tdyend As Date
Dim myAppointments As Outlook.Items
Dim currentAppointment As Outlook.AppointmentItem
Set myNameSpace = Application.GetNamespace("MAPI")
tdystart = VBA.Format(Now, "Short Date")
tdyend = VBA.Format(Now + 1, "Short Date")
Set myAppointments = myNameSpace.GetDefaultFolder(olFolderCalendar).Items
Set currentAppointment = myAppointments.Find("[Start] >= """ & tdystart & """ and [Start] <= """ & tdyend & """")
While TypeName(currentAppointment) <> "Nothing"
MsgBox currentAppointment.Subject
Set currentAppointment = myAppointments.FindNext
Wend
End Sub
See the following articles for more information and sample code:
How To: Use Find and FindNext methods to retrieve Outlook mail items from a folder (C#, VB.NET)
How To: Use Restrict method to retrieve Outlook mail items from a folder
Also you may find the AdvancedSearch method of the Application class helpful. The key benefits of using the AdvancedSearch method are listed below:
The search is performed in another thread. You don’t need to run another thread manually since the AdvancedSearch method runs it automatically in the background.
Possibility to search for any item types: mail, appointment, calendar, notes etc. in any location, i.e. beyond the scope of a certain folder. The Restrict and Find/FindNext methods can be applied to a particular Items collection (see the Items property of the Folder class in Outlook).
Full support for DASL queries (custom properties can be used for searching too). You can read more about this in the Filtering article in MSDN. To improve the search performance, Instant Search keywords can be used if Instant Search is enabled for the store (see the IsInstantSearchEnabled property of the Store class).
You can stop the search process at any moment using the Stop method of the Search class.
Second, I always suggest releasing underlying COM objects instantly. Use System.Runtime.InteropServices.Marshal.ReleaseComObject to release an Outlook object when you have finished using it. Then set a variable to Nothing in Visual Basic (null in C#) to release the reference to the object. You can read more about that in the Systematically Releasing Objects article.
If you want to use GC, you need to call the Collect and WaitForPendingFinalizers methods twice.
Matt, you still don't release all objects in the code. For example:
for (int i = 0; i < FolderToSearch.Items.Count; ++i)
{
COMObject item = FolderToSearch.Items[i];
The Items property of the Folder class returns an instance of the corresponding class which should be released after. I see at lease two lines of code where the reference counter is increased.

Asp.net's AutoEventWireup and reflection?

AutoEventWireup uses reflection searching page methods by page_eventName
msdn
When AutoEventWireup is true, handlers are automatically bound to
events at run time based on their name and signature. For each event,
ASP.NET searches for a method that is named according to the pattern
Page_eventname, such as Page_Load or Page_Init.
Question :
Does he do it for every request ?
I looked in the temporary internet files (at Microsoft.net folder...) to see if he saves another file which contains explicit handler attachment - and couldn't find any .
It seems that ASP.NET uses cache for that as #Marc said. See internal TemplateControl.HookUpAutomaticHandlers.
A part of this method by using dotPeek:
internal void HookUpAutomaticHandlers()
{
...
object obj = TemplateControl._eventListCache[(object) this.GetType()];
if (obj == null)
{
lock (TemplateControl._lockObject)
{
obj = TemplateControl._eventListCache[(object) this.GetType()];
if (obj == null)
{
IDictionary local_1_1 = (IDictionary) new ListDictionary();
this.GetDelegateInformation(local_1_1);
obj = local_1_1.Count != 0 ? (object) local_1_1 : TemplateControl._emptyEventSingleton;
TemplateControl._eventListCache[(object) this.GetType()] = obj;
}
}
}
...
Private GetDelegateInformation method is responsible for creating delegates for the control.
TemplateControl._eventListCache is a Hashtable which holds delegates per template control.
So, answering your question:
Does he do it for every request ?
The answer is no. ASP.NET does it once to populate this Hashtable, and then uses cached values.

Custom workflow activity errors 'Value cannot be null'

I'm creating a custom workflow activity in VS2010 targeting .NET 3.5. The DLL is actually being used in a Microsoft System Center Service Manager custom workflow, but I don't think that is my issue.
I have a public string property, that the user types in the string of what the activity should use. However, when the WF runs, it errors out 'value cannot be null'. I want to target if it is my code or something else.
When we drag my custom activity onto the designer, I'm able to type in the text of the string on the designer for that property.
public static DependencyProperty ChangeRequestStageProperty = DependencyProperty.Register("ChangeRequestStage", typeof(String), typeof(UpdateChangeRequestStage));
[DescriptionAttribute("The value to set the ChangeRequestStage Property in the ChangeRequest Extension class.")]
[CategoryAttribute("Change Request Extension")]
[BrowsableAttribute(true)]
[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
public String Stage
{
get { return ((String)(base.GetValue(UpdateChangeRequestStage.ChangeRequestStageProperty))); }
set { base.SetValue(UpdateChangeRequestStage.ChangeRequestStageProperty, value); }
}
protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
{
EnterpriseManagementGroup emg = CreateEMG();
//System.WorkItem.ChangeRequest Extension - ClassExtension_928bec0a_cac4_4a0a_bd89_7146c9052fbe
ManagementPackClass mpcChangeRequest = emg.EntityTypes.GetClass(new Guid("8c6c6057-56ad-3862-47ec-dc0dde80a071"));
//System.WorkItemContainsActivity Relationship Class
ManagementPackRelationship workItemContainsActivityRelationship = emg.EntityTypes.GetRelationshipClass(new Guid("2DA498BE-0485-B2B2-D520-6EBD1698E61B"));
EnterpriseManagementObject changeRequest = null;
//Loop thru each emo (Change Request in this case), and assign it. There will never be more than 1 emo returned
foreach (EnterpriseManagementObject obj in emg.EntityObjects.GetRelatedObjects<EnterpriseManagementObject>(executionContext.ContextGuid, workItemContainsActivityRelationship, TraversalDepth.OneLevel, ObjectQueryOptions.Default))
{ changeRequest = obj; }
EnterpriseManagementObjectProjection emop = new EnterpriseManagementObjectProjection(changeRequest);
if (emop != null)
{ emop.Object[mpcChangeRequest, "ChangeRequestStage"].Value = Stage; }
emop.Commit();
return base.Execute(executionContext);
}
Since it is getting a 'value cannot be null' error, I'm guessing it's on this line:
emop.Object[mpcChangeRequest, "ChangeRequestStage"].Value = Stage;
I'm going to test and see if hardcoding a value works or not. Any ideas?
enter code here
try this
if (emop != null && emop.Object[mpcChangeRequest, "ChangeRequestStage"] != null)
emop.Object[mpcChangeRequest, "ChangeRequestStage"].Value = Stage
I didn't want to leave this question wide open, so I'm updating it as to how I resolved this (a long time ago).
Rather than working with an EnterpriseManagementObjectProjection (emop), I worked with a standard EnterpriseManagementObject (emo). From there, I was able to follow a similar format from above:
ManagementPackClass mpcChangeRequest = emg.EntityTypes.GetClass(new Guid("8c246fc5-4e5e-0605-dc23-91f7a362615b"));
changeRequest[mpcChangeRequest, "ChangeRequestStage"].Value = this.Stage;
changeRequest.Commit();

Categories

Resources