NullReferenceException after long period of uptime - asp.net

I've got an ASP.Net application, which starts throwing NUllReferenceExceptions, after a long period of running. The code in question is used early on in each individual session, where we're trying to establish some kind of referrer information. The thing is, I can't fathom out what can throw this exception.
The method in question (topmost in the stack trace) is:
Private Function ResolveReferrer(ByVal wrRequest As HttpRequest) As Referral
'1) If we don't find a domain, try and get a match on any query strings
If wrRequest.QueryString.Count > 0 Then
For Each item As Referral In Me
For Each sKey As String In wrRequest.QueryString.Keys
If Not sKey Is Nothing AndAlso item.Names.Contains(sKey.ToLower) Then
Return item
End If
Next sKey
Next item
End If
Dim strSubDomain As String = Utility.RequestSubDomain(wrRequest.Url)
'2) If we don't find one on the domain, see if we can find the domain in query string
If Not wrRequest.QueryString.Item("domain") Is Nothing Then
strSubDomain = wrRequest.QueryString.Item("domain")
strSubDomain = HttpUtility.UrlDecode(strSubDomain)
' OK found a "domain" query string, so make up a referrer object to return
' ... just use the domain we've found for all the parameters
Dim oRef As New Referral(strSubDomain, strSubDomain, strSubDomain)
Return oref
End If
'3) If no query string of "domain", then see if the referring field is presented by the browser
If Not wrRequest.UrlReferrer Is Nothing Then
Dim sURL As String = wrRequest.UrlReferrer.ToString
strSubDomain = Utility.RequestSubDomain(wrRequest.UrlReferrer)
Dim oRef As New Referral(sURL, sURL, strSubDomain)
Return oRef
End If
'4) See if we can find the domain defined in the web.config
For Each item As Referral In Me
' See if we can find a referrer from the domain name
If String.Compare(strSubDomain, item.FromDomain, False) = 0 Then
Return item
End If
Next item
'5) If we still can't find one, make one up with a value of "Unknown"
Return New Referral("Unknown", "Unknown", "Unknown", "Unknown")
End Function
The class that this is a part of inherits from ArrayList. I've checked, and the only things added to this ArrayList are instances of the Referral class (which has multiple constructors, all simple).
What we do know is that, we can have a request that comes in with no referrer information, and it causes the exception to be thrown. At the same time, if a request with a referrer comes in, it works fine. In neither case is anything passed in the query string (so I think you can skip down to the '3 comment.
So, my question is, what in this method can cause a NullReferenceException to be thrown? If you need additional snippets added, or class definitions, just shout.
Utility.RequestSubDomain has reasonable complexity, so I doubt that it's being inlined and removed from the stack trace. And it's top is:
Public Shared Function RequestSubDomain(ByVal uri As System.Uri) As String
If uri Is Nothing Then
Return ""
End If
Any help, or suggestions for finding more information would be appreciated. It's obviously (as with so many problems) only happening in production, so I don't want to switch on debugging.

I took a good hard look and the only two things that come to mind that seem like the most likely are:
wrRequest could be null.
The ArrayList could have null values in it resulting in an enumerator that returns null values.
If it were me I would first focus my attention on this section. Is there any way possible that the Me.GetEnumerator will return an enumerator with one of the items having a null value?
For Each item As Referral In Me
item.Names ' Can item be null here causing the exception on the getter of Names?
Next item

As it turned out, there was a NULL in the arraylist - it turns out that, in certain circumstances, multiple threads were working on the same object (which inherits from arraylist) and calling Add(). So the null was appearing because the internal index was being incremented twice by different threads.

Related

Trying to search Active Directory using Ambiguous Name Resolution but it never returns anything

Unable to get it to return any results. Compiles fine and does not error when it is run, but the results are always empty.
I have got this working if I restrict it to something like DisplayName or given name. But would like it to work no matter if the user puts in forename or surname first and that the user is not restricted to adhering to the DisplayName format of "Surname, Forename"
Dim searchterm As String = RouteData.Values("Search")
Dim domain As New PrincipalContext(ContextType.Domain, "Domain")
Dim user As New CustomUserPrincipal(domain)
Dim search As New PrincipalSearcher()
Dim results As PrincipalSearchResult(Of Principal)
jss.MaxJsonLength = Integer.MaxValue
user.Anr = String.Format("*{0}*", searchterm)
search.QueryFilter = user
CType(search.GetUnderlyingSearcher, DirectoryServices.DirectorySearcher).SizeLimit = 25
results = search.FindAll()
<DirectoryObjectClass("user")>
<DirectoryRdnPrefix("CN")>
Public Class CustomUserPrincipal
Inherits UserPrincipal
Public Sub New(context As PrincipalContext)
MyBase.New(context)
End Sub
<DirectoryProperty("anr")>
Public Property Anr As String
Get
Return CStr(ExtensionGet("anr")(0))
End Get
Set(value As String)
ExtensionSet("anr", value)
End Set
End Property
End Class
I am expecting an object that I can enumerate through and pull out individual UserPrincipals to extract details. But I only get an empty object
I think this is your problem:
user.Anr = String.Format("*{0}*", searchterm)
Specifically, that you're putting asterisks around your search term. According to the documentation, it will expand a search term like (anr=Smith) to something like this:
(|(displayName=smith*)(givenName=smith*)(legacyExchangeDN=smith)(physicalDeliveryOfficeName=smith*)(proxyAddresses=smith*)(Name=smith*)(sAMAccountName=smith*)(sn=smith*))
Notice that it already does a "starts with" type search. Putting your own wildcards in there messes it up.
More specifically, it's the asterisk at the beginning. I tested this in our own AD environment. If I search for (anr=*Gabriel*) or (anr=*Gabriel), I get no results. If I search for (anr=Gabriel*) I get results, but it really has no effect on the results (the results are the same as if I had searched for (anr=Gabriel)).
The solution is to change that line to this:
user.Anr = searchterm
It is not exactly equivalent to the "contains" search you seem to want, but putting a wildcard at the beginning of any search really kills performance anyway. It can no longer use any indexes to complete the search, so it's forced to look at every user account in your domain.

In ASP.NET, trying to find the assigned visibility value of a control that may be inside an invisible container

I am trying to find out whether a particular control on an asp.net page has had it's "Visible" property assign to true or false. The problem is that the visible property crawl up the list of parents and if any of them show as invisible, the queried control will also show as invisible. I need to know what the control itself has been set to.
I did some searching and found the post How to get the set/real value of the Visible property in Asp.Net which offered the following solution
public static bool LocalVisible(this Control control){
var flags = typeof (Control)
.GetField("flags", BindingFlags.Instance | BindingFlags.NonPublic)
.GetValue(control);
return ! (bool) flags.GetType()
.GetProperty("Item", BindingFlags.Instance | BindingFlags.NonPublic)
.GetValue(flags, new object[] {0x10});
}
But when I tried it, it returned an "Ambiguous Match Found" error on GetProperty.
Can someone point out what I'm doing wrong, or show another way of getting what I want?
I had the same problem (two years later). This is the answer that I just wrote in the topic that you refer to:
In case someone tries to get Jørn Schou-Rode's code working in VB.NET, here is the code that works for me. When I simply translate his code in VB, I get an "Ambiguous match found" exception, because there are 3 flavors of the flags "Item" property.
<Extension()>
Public Function GetLocalVisible(ctl As Control) As Boolean
Dim flags As Object = GetType(Control).GetField("flags", BindingFlags.Instance Or BindingFlags.NonPublic).GetValue(ctl)
Dim infos As PropertyInfo() = flags.GetType().GetProperties(BindingFlags.Instance Or BindingFlags.NonPublic)
For Each info As PropertyInfo In infos
If info.Name = "Item" AndAlso info.PropertyType.Name = "Boolean" Then
Return Not CBool(info.GetValue(flags, New Object() {&H10}))
End If
Next
Return ctl.Visible
End Function

Asp.net pass value from txtbox to an another page

This the end of my code
...
If lblErrMsg.Text = "" Then
Response.Redirect("UserPage.aspx")
End If
I want to pass the value of txtUser(I create It in the current page...) to the UserPage.aspx.
Thank's for helping me ...
This is in VB.net not in c# Please
C# Version
1) Use querystring
Response.Redirect("user.aspx?val="+txtBox.Text);
and in userp.aspx.cs,
string strVal=Request.QueryString["val"];
2)Use Session
Setting session in first page before redirecting
Session["val]=txtBox.Text;
Response.Redirect("user.aspx");
and in user.aspx.cs
String strVal=(string) Session["val"];
EDIT :VB.NET VERSION
1) Use Querystring
Response.Redirect("user.aspx?val=" + txtBox.Text)
and in user.aspx.vb
Dim strVal As String = Request.QueryString("val")
2)Use Session
Setting Session in firstpage
Session("val")=txtBox.Text
Response.Redirect("user.aspx")
and in user.aspx.vb.
Dim strVal As String = DirectCast(Session("val"), String)
You can pass it in the query string, like this:
Response.Redirect("UserPage.aspx?user=" + HttpUtility.UrlEncode(txtUser.Text));
And then retrieve it via:
string user = Request.QueryString["user"];
If you're worried about users messing with a query string (be sure to validate it), you could also store a Session variable before doing the redirect.
warning: this is a gross but easy solution
Session("myTextbox")= txtUser.Text
this will persist the value so on the page_load of the next page you can say
txtUser.Text=Session("myTextBox")
What are you passing form page to page? Is it a list of things. You could have an object with different properties and could then pass it through a session. If you have multiple pages I would suggest doing this if you could end up reusing it else where. Passing it through the url, you would then need to validate it, because if someone types the url with the correct information or something that is being directly input into a database they could cause problems and/or unexpected results.

Entity Framework: Insists on adding new entity in many-to-many instead of re-using existing FK

I have got a many to many relationship, briefly
Cases -----< CaseSubjectRelationships >------ CaseSubjects
More fully:
Cases(ID, CaseTypeID, .......)
CaseSubjects(ID, DisplayName, CRMSPIN)
CaseSubjectsRelationships(CaseID, SubjectID, PrimarySubject, RelationToCase, ...)
In my many-to-many link table are additional properties relating to the subject's association with the specific case - such as, start date, end date, free-text relationship to case (observer, creator, etc)
An Entity Framework data model has been created - ASP.NET version 4.0
I have a WCF service with a method called CreateNewCase which accepts as its parameter a Case object (an entity created by the Entity Framework) - its job is to save the case into the database.
The WCF service is invoked by a third party tool. Here is the SOAP sent:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<CreateNewCase xmlns="http://tempuri.org/">
<c xmlns:a="http://schemas.datacontract.org/2004/07/CAMSModel">
<a:CaseSubjectsRelationships>
<a:CaseSubjectsRelationship>
<a:CaseSubject>
<a:CRMSPIN>601</a:CRMSPIN>
<a:DisplayName>Fred Flintstone</a:DisplayName>
</a:CaseSubject>
<a:PrimarySubject>true</a:PrimarySubject>
<a:RelationToCase>Interested</a:RelationToCase>
<a:StartDate>2011-07-12T00:00:00</a:StartDate>
</a:CaseSubjectsRelationship>
<a:CaseSubjectsRelationship>
<a:CaseSubject>
<a:CRMSPIN>602</a:CRMSPIN>
<a:DisplayName>Barney Rubble</a:DisplayName>
</a:CaseSubject>
<a:RelationToCase>Observer</a:RelationToCase>
<a:StartDate>2011-07-12T00:00:00</a:StartDate>
</a:CaseSubjectsRelationship>
</a:CaseSubjectsRelationships>
<a:CaseType>
<a:Identifier>Change of Occupier</a:Identifier>
</a:CaseType>
<a:Description>Case description</a:Description>
<a:Priority>5</a:Priority>
<a:QueueIdentifier>Queue One</a:QueueIdentifier>
<a:Title>Case title</a:Title>
</c>
</CreateNewCase>
</s:Body>
</s:Envelope>
The WCF engine deserializes this into a Case entity for me correctly and when I look in the debugger everything is set up properly.
What I want to do, is only create a new CaseSubject if there is not already an entry in the database with that CRMSPIN specified (CRMSPIN is a reference number from a central customer database)
So, in the below example, I want to see if I already have an entry in CaseSubjects for somebody with CRMSPIN 601 and if I do, I don't want to create another (duplicate) entry but instead make the new case link to the existing subject (although a new row will need, obviously, need creating in CaseSubjectsRelationships with the specific 'additional' information such as relationship etc)
Here is the .NET code I have tried to do this.
Public Class CamsService
Implements ICamsService
Public Function CreateNewCase(c As CAMSModel.Case) As String Implements ICamsService.CreateNewCase
Using ctx As New CAMSEntities
' Find the case type '
Dim ct = ctx.CaseTypes.SingleOrDefault(Function(x) x.Identifier.ToUpper = c.CaseType.Identifier.ToUpper)
' Give an error if no such case type '
If ct Is Nothing Then
Throw New CaseTypeInvalidException(String.Format("The case type {0} is not valid.", c.CaseType.Identifier.ToString))
End If
' Set the case type based on that found in database: '
c.CaseType = ct
For Each csr In c.CaseSubjectsRelationships
Dim spin As String = csr.CaseSubject.CRMSPIN
Dim s As CaseSubject = ctx.CaseSubjects.SingleOrDefault(Function(x) x.CRMSPIN = spin)
If Not s Is Nothing Then
' The subject has been found based on CRMSPIN so set the subject in the relationship '
csr.CaseSubject = s
End If
Next
c.CreationChannel = "Web service"
c.CreationDate = Now.Date
' Save it '
ctx.AddToCases(c)
ctx.SaveChanges()
End Using
' Return the case reference '
Return c.ID.ToString
End Function
End Class
As you can see, instead the For Each loop, I try to get a subject based on the CRMSPIN and if I get something, then I update the "CaseSubject" entity. (I have also tried csr.SubjectID = s.ID instead of setting the whole entity and also I have tried setting them both!).
However, even when putting a breakpoint on the ctx.SaveChanges() line and looking at how the subjects are set up and seeing in the debugger that it looks fine, it is always creating a new row in the CaseSubjects table.
I can see in principle this should work - you'll see I've done exactly the same thing for Case Type - I have picked the identifier sent in the XML, found the entity with that identifier via the context, then changed the case's .CaseType to the entity I found. When it saves, it works perfectly and as-expected and with no duplicated rows.
I'm just having trouble trying to apply the same theory to one side of a many-to-many relationship.
Here are some (hopefully relevant) extracts from the .edmx
<EntitySet Name="Cases" EntityType="CAMSModel.Store.Cases" store:Type="Tables" Schema="dbo" />
<EntitySet Name="CaseSubjects" EntityType="CAMSModel.Store.CaseSubjects" store:Type="Tables" Schema="dbo" />
<EntitySet Name="CaseSubjectsRelationships" EntityType="CAMSModel.Store.CaseSubjectsRelationships" store:Type="Tables" Schema="dbo" />
<AssociationSet Name="FK_CaseSubjectsRelationships_Cases" Association="CAMSModel.Store.FK_CaseSubjectsRelationships_Cases">
<End Role="Cases" EntitySet="Cases" />
<End Role="CaseSubjectsRelationships" EntitySet="CaseSubjectsRelationships" />
</AssociationSet>
<AssociationSet Name="FK_CaseSubjectsRelationships_CaseSubjects" Association="CAMSModel.Store.FK_CaseSubjectsRelationships_CaseSubjects">
<End Role="CaseSubjects" EntitySet="CaseSubjects" />
<End Role="CaseSubjectsRelationships" EntitySet="CaseSubjectsRelationships" />
</AssociationSet>
EDIT: The property setters for the CaseSubject property of the CaseSubjectsRelationships object:
/// <summary>
/// No Metadata Documentation available.
/// </summary>
<XmlIgnoreAttribute()>
<SoapIgnoreAttribute()>
<DataMemberAttribute()>
<EdmRelationshipNavigationPropertyAttribute("CAMSModel", "FK_CaseSubjectsRelationships_CaseSubjects", "CaseSubject")>
Public Property CaseSubject() As CaseSubject
Get
Return CType(Me, IEntityWithRelationships).RelationshipManager.GetRelatedReference(Of CaseSubject)("CAMSModel.FK_CaseSubjectsRelationships_CaseSubjects", "CaseSubject").Value
End Get
Set
CType(Me, IEntityWithRelationships).RelationshipManager.GetRelatedReference(Of CaseSubject)("CAMSModel.FK_CaseSubjectsRelationships_CaseSubjects", "CaseSubject").Value = value
End Set
End Property
You didn't specify what context model are you working with, so I'll assume you're using the default (ie. you don't have some explicit .tt files to generate your entities).
So, basically, this is what I think is happening.
In your code, when you fetch something from context:
Dim ct = ctx.CaseTypes.SingleOrDefault(Function(x) x.Identifier.ToUpper = c.CaseType.Identifier.ToUpper)
this ct is in context. The method argument that you deserialized from service (the c) is not in context. You can regard the context as the "object tracking and fetching" entity, that makes sure that everything attached to it can know about any changes, if it's new, deleted etc.
So, when you get to the part:
' Set the case type based on that found in database: '
c.CaseType = ct
at the moment you assign something that's attached to something not attached, the unattached object will get pulled into context as well - there can't be "partially" attached entities - if it's attached, everything it references has to be attached as well. So, this is the moment where the c gets "dragged" into the context (implicitly). When it enters the context, it will get marked as "new" since it doesn't know anything about it yet (it has no knowledge of it, no change tracking info...).
So, now that everything about that object c is in context, when you query the context for this:
Dim s As CaseSubject = ctx.CaseSubjects.SingleOrDefault(Function(x) x.CRMSPIN = spin)
it will figure that indeed there is an object with that CRMSPIN and it's already attached - "hey, no need to go to database, I already have this!" (trying to be smart and avoid a db hit), and it will return your own object.
Finally, when you save everything, it will be saved, but your attached c and all of it's child objects that are marked as 'new' will be inserted instead of updated.
The easiest fix would be to first query everything you need from context, and only then start assigning it to properties of your object. Also, take a look at UpdateCurrentValues, it may also be helpful...
OK: So the resolution to this was a combination of what #veljkoz said in his answer (which was very useful to help me out to reach the final resolution, but on its own was not the full resolution)
By moving the For Each loop to the first thing done before anything else (As hinted by #veljkoz), that got rid of the Collection was modified, enumeration may not continue error I was getting when I set csr.CaseSubject = Nothing.
It also turned out to be important to not attach entities (e.g. not to set csr.CaseSubject to an entity but only to Nothing) but instead to use the .SubjectID property. A combination of all the above led me to the following code, which works perfectly and doesn't try to insert duplicate rows.
+1 to #veljkoz for the assist but also note that the resolution includes setting the entity reference to Nothing and using the ID property.
Full, working code:
Public Function CreateNewCase(c As CAMSModel.Case) As String Implements ICamsService.CreateNewCase
Using ctx As New CAMSEntities
' Subjects first, otherwise when you try to set csr.CaseSubject = Nothing you get an exception '
For Each csr In c.CaseSubjectsRelationships
Dim spin As String = csr.CaseSubject.CRMSPIN
Dim s As CaseSubject = ctx.CaseSubjects.SingleOrDefault(Function(x) x.CRMSPIN = spin)
If Not s Is Nothing Then
' The subject has been found based on CRMSPIN so set the subject in the relationship '
csr.CaseSubject = Nothing
csr.SubjectID = s.ID
End If
Next
' Find the case type '
Dim ct = ctx.CaseTypes.SingleOrDefault(Function(x) x.Identifier.ToUpper = c.CaseType.Identifier.ToUpper)
' Give an error if no such case type '
If ct Is Nothing Then
Throw New CaseTypeInvalidException(String.Format("The case type {0} is not valid.", c.CaseType.Identifier.ToString))
End If
' Set the case type based on that found in database: '
c.CaseType = ct
c.CreationChannel = "Web service"
c.CreationDate = Now.Date
' Save it '
ctx.AddToCases(c)
ctx.SaveChanges()
End Using
' Return the case reference '
Return c.ID.ToString
End Function

sending Json array failed

I am building a JSON/WCF app and need to send an array of objects back to the server. For some reason it is not accepting the array. Using script manager I can get data fine.
var month = $("#ddlStartMonth").val();
var year = $("#ddlStartYear").val();
var items = JSON.stringify(calendarItems);
WebService.SaveCalendar(items, new Date(year, month, 01).toDateString(), new Date(year, month, 01).toDateString(), Submit, onPageError);
I have tried with and without the JSON stringify. The function onPageError is activated and the only error info it produces is "The server method 'SaveCalendar' failed". Yet the breakpoint on the first line of the web method is not activated.
<OperationContract()>
<WebGet(ResponseFormat:=WebMessageFormat.Json, BodyStyle:=WebMessageBodyStyle.WrappedRequest)>
<WebMethod(EnableSession:=True)>
Public Function SaveCalendar(ByVal _jsonImages As String()(), ByVal _selectedMonth As String, ByVal _selectedYear As String) As Boolean
Dim _calenderItems As New List(Of CalenderItem)
'_calenderItems = New JavaScriptSerializer().Deserialize(Of List(Of CalenderItem))(_jsonImages)
HttpContext.Current.Session("calenderItems") = _calenderItems
HttpContext.Current.Session("selectedMonth") = New Date(_selectedMonth)
HttpContext.Current.Session("selectedYear") = New Date(_selectedYear)
Return True
End Function
Any Ideas?
I've had similar issues working with MVC. I think .NET's deserializer actually expects that the object it is passed will be a JSON object rather than an array (i.e. it should always start with "{" and end with "}". You could:
Create a POCO class to act as your DTO which simply has a List/Array of CalenderItems inside of it, or
Use a more "lenient" deserializer like Newtonsoft's JSON.NET
Of course this second option would only work if you can somehow convince WCF to run the method in the first place. Looking at your code again, though, I'm wondering if your declaring _jsonImages as a double-array of strings might be causing some difficulty.

Resources