Archiwum kategorii: ASP.NET

Sys.WebForms.PageRequestManagerParserErrorException in an intranet-zone web application (IE)

Hi there,

this time I’d like to describe a pretty odd issue encountered a while ago.

We have a following scenario: We have an ASP.NET 4 web application, configured in IIS 7 only for basic authentication. The application uses quite a lot AJAX update panels and other javascripts. The problem that started occuring was the infamous Sys.WebForms.PageRequestManagerParserErrorException:

—————————
Microsoft Internet Explorer
—————————
Sys.WebForms.PageRequestManagerParserErrorException: The message received from the server could not be parsed. Common causes for this error are when the response is modified by calls to Response.Write(), response filters, HttpModules, or server trace is enabled.

Details: Error parsing near ScriptResource.axd ….

It happened only using IE (v.7,8,9), but since IE has  always been a bit „different”, that was not the funniest fact about the problem. What was in fact strange, was that it happened only on some machines – I’ll come back to that later in this post.

However, all the hints pointing how to avoid that error failed. In fact, the application did not have any calls to Response.Write, Server.Transfer, neither http modules nor response filters. Trace was also disabled.

Not the first time, Fiddler came to rescue. I was able to notice that for each needed request for an aspx page, actually two requests were made. The first one was giving a HTTP status code 401 (access denied), then the second one was successful (HTTP 200). Analyzing the request headers the only difference between them was the authorization method. The request which gave 401 response had:

Authorization: NTLM DFGHJKLDRFGHNXAAAAA==

The second one had :

Authorization: Basic ZXVyasdasdasdasdasdasd=

Since the update panel and other asynchronous requests were getting a 401 response, the application was giving the error mentioned above.

Now, the question was, why would the NTLM authorization be enabled, if I had set explicitly in IIS the windows authentication method to be disabled? As mentioned earlier, only basic authentication was enabled. Since this app was also a sub-application of another one (which had windows authentication enabled), first thought was an inheritance problem of IIS settings. But the app having problems was overriding the parent setting (win auth disabled), so from that point of view it was OK.

As mentioned already earlier, the issue was occuring on some machines only. And there was the rub. The machines were the corporate ones of our company, and the website was added as an intranet site in Internet options. Additionally, the automatic logon for intranet zone was enabled:

automatic logon only in intranet zone

This setting is forcing Internet Explorer first to try to authorize the user logged onto the machine in the domain. That failed, since NTLM/Windows auth was disabled in IIS. First then the ‚correct’ basic authentication request was made.

As a solution you may either remove the application from intranet sites (if your/corporate policy allows it), or you may enable Windows authentication in the application instead of the basic one.

Hope it helps,
Łukasz

MOSS Search web service – impersonation problems when calling from an external application

Hi there,

A while ago I was implementing a search functionality within an ASP.NET application. The plan was to use the SharePoint Search for crawling and indexing the contents, and afterwards, from my application, connect to the MOSS web service and perform the needed query upon it.

I had some web sites and BDC applications prepared within a scope; everything crawled and indexed – so far so good.

In the ASP.NET application, the service reference to the exposed asmx has been added (e.g. http://sharepoint/_vti_bin/search.asmx ).
Then I tried to invoke the service sending a query packet xml object:
[csharp]QueryServiceSoapClient client = new QueryServiceSoapClient();

client.Query ("<QueryPacket>….");[/csharp]
At this stage, the following exception occurred:

Error:
Retrieving the COM class factory for component with {CLSID BDEADEE2-C265-11D0-BCED-00A0C90AB50F} failed due to the following error: 80070542

It doesn’t say much, does it? After some reading, it came out that the app could not authenticate itself against the MOSS webservice in a correct manner – the credentials for the webservice weren’t passed as one would expect.
Of course, an explicit assignment of username and password was not the way I wanted to go. I needed the application pool account (which had all needed permissions on the webervice) to be used and impersonated on every call to the asmx.

Changing the client’s impersonation level to ‚Delegation’ solved the issue:
[csharp]client.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Delegation;[/csharp]
Exception gone, search results present.
Hope this helps,
Łukasz

SharePoint: „Loading this assembly would produce a different grant set from other instances” after a security patch from MS

Hello,

after installing the critical patches for .NET framework, as described in the MS Security Bulletin MS11-100, some of our MOSS 2007 applications were hitting the following exception:

FileLoadException : Loading this assembly would produce a different grant set from other instances. (Exception from HRESULT: 0x80131401

It seems that the security fix applied in the patch KB2657424 (maybe also KB2656351, although it’s a different version of .NET framework) has caused this temporary problem. The solution is to recycle the affected applications’ IIS pool – the exceptions don’t occur anymore and applications work correctly again.
The solution with restarting application pools appears to be quite strange, since the whole machine had to be restarted upon installation of those security updates. But still, it worked.

Hope this helps,
Łukasz

ASP.NET membership provider – identifying users in a multi-domain Active Directory

Hello there,

in a case when using ASP.NET membership provider against Active Directory (System.Web.Security.ActiveDirectoryMembershipProvider), and when there is more than one domain within the directory, one may encounter a trouble distinctly identifying users. E.g. DOMAIN1userXY is a different user than DOMAIN2userXY. Thus, the users must not be confused and should be treated with caution.

In the web.config entry for the membership provider we can specify which field of the AD object should be checked in order to precisely find the user we mean. The attribute „attributeMapUsername” has two possible values:

  1. sAMAccountName
  2. userPrincipalName

As of the first case, we have only the username – without domain – hence we cannot identify precisely which user is referenced. The second option gives us exactly what we need: the username with domain is used here (UserName@DomainName), thus we have the distinct identification of the users.

If you’re using the membership provider’s methods in codebehind, in this blog post you’ll find the explanation on how to fetch the needed properties of an Active Directory user needed as provider’s method parameters. They are stored in the UserPrincipal object.

Hope this helps,
Łukasz

ASP.NET: asynchronous calls to session-enabled web service methods

Howdy,

This time a small hint for those of you that are using jQuery and/or AJAX methods to connect with an ASP.Net web service, and the web service is using Session variables (web methods with [EnableSession=true] attribute).

I have been using this approach for some time, since I needed to persist some data for users.

However, when it came to performance tests, it occurred that the AJAX calls weren’t really asynchronous. The tests revealed that each next call waits for the previous one to finish.

The reason is quite simple and is one of ASP.net’s limitations: the first request gains exclusive access to the session and its variables, and thus prevents execution of next request until the current one completes. My approach was wrong and it took a while to discover the cause. Maybe if I had read the last paragraph of this article  first, it would have been easier 😉

So, for having better performance of concurrent request in a similar architecture, one would have to either use other ASP.net methods for persisting state (like Cache object), or write a custom solution.

Hope this helps,

Łukasz

Posted from WordPress for Android

„Membership credential verification failed”

Hello,

there is quite a lot of writing across the web on this ASP.net issue:

Membership credential verification failed.
(…)
Name to authenticate: userXYZ

When you have role, memberhip, or other providers configured in your ASP.net application, you have to remember to set the ApplicationName property in each of the provider entries in your web.config file. That’s clear. But what if the message still comes up?

In my case I was using forms authentication against Active Directory with a custom role provider. The odd thing was that only a few of the users could not perform a correct login. Others were signing in just ok. So, after checking the AD properties of the user objects (there was a suggestion that it may be caused by similar objects in different OU’s), then analyzing the role logic of the custom provider, nothing seemed to be causing the trouble.

The actual reason was very simple. The users which had problems signing in had cookies disabled in their browsers, hence the forms authentication could not store the session data on client side. So, one should have in mind, that the windows server log entries with the „Membership credential verification failed” information message could also be caused by such a trivial thing as unavailable cookies in user’s browsers.

Hope this helps,
Łukasz

Verbs configuration for custom HTTP handlers

Hello,

if your ASP.NET or Sharepoint web application is storing binary data (images, PDF’s) in a database, you’ll probably need a HTTP handler which would retrieve those files from DB, and then transfer them to the user’s browsers as well as set the correct content type of the response. A clever way to do that is using the IHttpHandler interface, but that’s not the point of this entry.

Assuming that we have our handler ready and working, for example, reading jpegs from the DB and presenting them to the public as if it were normal files on the server (www.example.com/name1.jpg). In order for our Sharepoint Web Application to map such request onto a correct handler, we need a web.config entry within the <httpHandlers> section, like this:

<add verb="GET" path="/*.jpg" validate="false" 
type="MyAssembly.MyHandler, MyAssembly, 
Version=1.0.0.0, Culture=neutral, PublicKeyToken=abcdefghi"
/>

The verb attribute defines allowed HTTP request methods for this handler. In the case above, a HTTP POST request would be rejected by the server with a HTTP 404 code. For “normal” purposes, such as displaying the images in browsers, the GET method would be enough.

However, once you know that other clients than web browsers would access the handler, you must know which HTTP methods they’re using. Recently, thanks to Fiddler, I was able to discover that one of the client-apps used in our organization is using HEAD method (very similar to GET) in order to retrieve a file. Since the method was not enabled in our configuration, the client could not download the desired file.

Enabling the HEAD method within the handler’s verbs in web.config solves the issue:

<add verb="GET,HEAD" path="/*.jpg" (...) />

Hope this helps,
Łukasz

Request validation in ASP.Net 4.0

Hello again,

recently, while migrating one of our web applications to .NET Framework 4.0, we came across a following issue. The app’s main goal is to store some HTML articles in the database. However, when a user made a postback when saving an article, he got the following error message:

A potentially dangerous Request.Form value was detected from the client (ctl1…)

This kind of message is known to ASP.net 3.5 and 2.0 developers. The standard workaround for this issue was either to configure a single page not to validate request:

Page validateRequest=”false” 

..or, globally for the whole application, via web.config:

<pages validateRequest="false" />

We had the second option chosen, since only a couple of trusted and authenticated users were using the app. But, as already said, the error came up after migration to 4.0 Framework. The request validation was disabled in the <pages> node, but for ASP.Net 4.0 it seems not to be enough.

There are some security improvements in the latest version of ASP.Net, protecting from cross-site-scripting (XSS) attacks. New default protection not only applies to aspx pages, but to all kind of requests, like web service calls and custom handlers, even when using our custom HTTP module(s).

That was the reason why our app threw errors which it didn’t do before. In order to restore previous behavior of ASP.Net applications one has to set the request validation mode backwards, for the 2.0 version. In web.config, you just add following attribute to the <httpRuntime> node:

<httpRuntime requestValidationMode="2.0" />

Hope this helps.

Lukasz

Custom tags and attributes in a SyndicationItem

Hello again,

for those of you who are not quite satisfied with the standard syndication functionality of .Net, here is a small tip on how to extend the XML generated from the SyndicationFeed class in C#.

Let’s assume we would like to have a RSS feed, which in fact would serve as a podcast, e.g. for iTunes. The software from Apple uses some information from their custom-defined RSS-tags, with an “itunes” prefix, for example:

<itunes:author>Anonymous One</itunes:author>

Without this prefix it’s very easy. Our SyndicationItem class provides us a functionality to extend the standard item’s elements:

SyndicationItem item = new SyndicationItem();
item.ElementExtensions.Add("customTag", String.Empty, "My test");

The second attribute is the namespace which comes into play in the next step. In order to add the tag prefix as mentioned before, one has start with adding the namespace to the feed instance:

SyndicationFeed feed = new SyndicationFeed();
XmlQualifiedName n=new XmlQualifiedName("itunes","http://www.w3.org/2000/xmlns/");
String itunesNs = "http://www.itunes.com/dtds/podcast-1.0.dtd";
feed.AttributeExtensions.Add(n, itunesNs);

Now that we have added the new namespace to the feed, we can start adding custom item elements within that namespace.

SyndicationItem item = new SyndicationItem();
item.ElementExtensions.Add(new SyndicationElementExtension("author",
     itunesNs, "Famous author"));

That should solve the issue with custom tags with custom prefixes. One more thing.. it may be quite useful for those which attach media files to their podcasts: the enclosure tag.
In order to add such an element to the SyndicationItem, we can use the SyndicationLink object as follows:

SyndicationLink enclosure =
           SyndicationLink.CreateMediaEnclosureLink(
               new Uri("http://example.com/01.mp3"), "audio/mpeg", 1200);
item.Links.Add(enclosure);

The method takes three arguments: the URL , type (MIME-type) and length of media attachment.

Hope this helps.

Maintain selected tab position upon postback (jQuery UI Tabs)

Hello,

jQuery UI is a very nice add-on to the standard jQuery library. It provides us with out-of-the-box interactions and client side effects for a rich web application experience. One of the interesting effects are the jQuery tabs. They’re used to split the content into sections and be able to switch between them without having a postback, and also to spare some space within our web page.

The interaction is purely on the client side, so after reloading the page the tab which we selected as last isn’t maintained. What if we have, for example, a file upload control within one of our tab sections? After uploading a file (postback), we lose the focus on the tab in which we were previously.

But the developers of jQuery UI provide us with a couple of methods and events, which we can use to do some kind of workaround for this issue.

We need to have a document element which could store the selected tab index. We can use an input hidden field, value of which would be posted together with other data during page postback. So, let’s put it into our page, setting it’s value declaratively to 0 (the index of the first tab – default selection):

<input type="hidden" value="0" id="theHiddenTabIndex" />

Having the ID of the element, we can set its value from the client side script. Using the show event of the jQuery Tabs (fired when the tab is changed), we can do this at runtime:

$('#tabElmtId').tabs( {
  show: function() {
    var newIdx = $('#tabElmtId').tabs('option','selected');
    $('#theHiddenTabIndex').val(newIdx);
  }
 });

As you can see, when the event is triggered, the currently selected index of our tabs is being stored in a variable (line 3), then assigned as a value of the hidden input field. Now the postback can be performed but the next question is how to tell the tabs control to start from another tab index than the default 0.

First, on the server side, we can use the language which we prefer in order to fetch the value of the submitted hidden input field. For example, in ASP.net, it could look like this:

String hiddenFieldValue = Request.Form["theHiddenTabIndex"] ?? "0";

Now we can put javascript into our page’s source in order to tell have this variable also available for client side scripts:

   1: StringBuilder js = new StringBuilder();
   2: js.Append("<script type='text/javascript'>");
   3: js.Append("var previouslySelectedTab = ");
   4: js.Append(hiddenFieldValue);
   5: js.Append(";</script>");
   6: this.Header.Controls.Add(new LiteralControl(js.ToString()));

The one thing important about this is that it should be injected before the jQuery Tabs are initialised. Now the remaining task is to tell jQuery to use the javascript variable in order to set the selected tab upon loading the controls after postback. We can use the selected option of jQuery UI Tabs in order to assign this value:

   1: $('#tabElmtId').tabs( {
   2:     show: function() {
   3:         var newIdx = $('#tabElmtId').tabs('option','selected');
   4:         $('#theHiddenTabIndex').val(newIdx);
   5:     },
   6:     selected: previouslySelectedTab
   7: });

The only thing that changed from the previous Tabs initialisation is the line 6, where we assign the javascript variable to the selected option.
Now the tabs position should be postback-proof.

Happy jQuerying!