This has been a bad week. On Monday, one of my 3 servers died (hardware error - freezing intermittently). So I spent 24 hours porting all services off it onto my other 2 servers.
Then, overnight, one of those two servers had a major conniption.
I have no idea what the cause was, and I've never seen anything like it. All I know is that the server did a reboot as part of Automatic Windows Updates. And when it came back on, all of the NTFS permissions were borked.
And I mean really borked.
A *lot* of files had mysteriously lost their "Inherit Permissions" setting, so were now sitting there with only the owner allowed to access them.
This server now houses ALL websites, so the net result is that most websites were down as the files weren't readable by the NETWORK SERVICE account (used by ASP) or IUSR_XXXX (used by plain vanilla IIS).
In all, there were a squillion files on the system, and their permission settings were now all over the place. I tried just going to the PERMISSIONS tab of the root folder and setting its permissions, but it then sat there for 2 hours - presumably setting all child folders - but I was getting nervous as I was now waiting a long time for nothing to happen, whilst most sites were down.
The slow but fairly sure solution came in the form of xcacls.exe and xcacls.vbs - tools provided by Microsoft. xcacls.vbs particularly is VERY slow but seems to do the job.
I was able to run the following at the command prompt in order to get the current folder and all subfolders, and all files contained therein, to inherit their parent's permissions:
xcacls.vbs . /f /t /i enable
There's a caveat to that, though, which is that it didn't work on many folders as we didn't have permission - because those folders were owned by a small FTP user and I was logged in as Admin. So some tweaking was required.
I wounder up opening 6 command windows and having 6 instances run at once.
Whenever I met a folder that needed to have its permissions reset at the command prompt without using the Windows UI (which could mean waiting for a very long time), I'd run:
xcacls . /G Administrators:F
xcacls . /G System:F /E
xcacls . /G iusr_XXXXX:R /E
xcacls . /G "NETWORK SERVICE":R /E
Where XXXXX is the name of my server. That cleared the permissions for that folder alone.
What a headache. A *lot* of crawling ahead, but it seems under control now, so I can go and do other work... any work I can find that doesn't involve using any of the sites that are still down :(
Wednesday, August 26, 2009
Tuesday, May 26, 2009
(Probably not) the last word on Dynamic ASP.Net Controls
Dynamic ASP.Net controls are always a mystery to me.
That is, they always seem to be pretty straightforward but whenever I implement them I find things not going quite according to plan, and then spending a couple of days getting everything right. And then, a year or so later when I next need to implement them, I've forgotten everything and make the same mistakes again. Rinse and repeat.
The most common mistake, although one that I know well about so don't struggle with, is the question of when to create the controls. You need to create them on the Page_Init event so that the controls get into the page lifecycle early enough. This can sometimes lead to headaches as occasionally the decision as to what controls require creation isn't naturally resolved until Page_Load, but then you just need to be resourceful.
The problem that I do have, however, is events. Frequently I create dynamic controls in Page_Init, but when those controls trigger an event, the event doesn't fire.
Now, I'm not 100% sure of the details of the cause and effect link here, but after today's exploratory I can confirm that the fix for this is to ensure that whilst your controls need to be created and added under Page_Init, they should not be initialized until Page_Load.
This may well be a situational issue, but a problem that I've had lately with a button on a subcontrol not firing when added dynamically vanished when I simply split the creation logic from the initialization logic, and moved initialization to Page_Load and under a (if !Page.IsPostBack).
Will continue exploring, but when - in 2 years time - I'm next dabbling with dynamic controls, I hope I remember to read this first :)
That is, they always seem to be pretty straightforward but whenever I implement them I find things not going quite according to plan, and then spending a couple of days getting everything right. And then, a year or so later when I next need to implement them, I've forgotten everything and make the same mistakes again. Rinse and repeat.
The most common mistake, although one that I know well about so don't struggle with, is the question of when to create the controls. You need to create them on the Page_Init event so that the controls get into the page lifecycle early enough. This can sometimes lead to headaches as occasionally the decision as to what controls require creation isn't naturally resolved until Page_Load, but then you just need to be resourceful.
The problem that I do have, however, is events. Frequently I create dynamic controls in Page_Init, but when those controls trigger an event, the event doesn't fire.
Now, I'm not 100% sure of the details of the cause and effect link here, but after today's exploratory I can confirm that the fix for this is to ensure that whilst your controls need to be created and added under Page_Init, they should not be initialized until Page_Load.
This may well be a situational issue, but a problem that I've had lately with a button on a subcontrol not firing when added dynamically vanished when I simply split the creation logic from the initialization logic, and moved initialization to Page_Load and under a (if !Page.IsPostBack).
Will continue exploring, but when - in 2 years time - I'm next dabbling with dynamic controls, I hope I remember to read this first :)
Thursday, March 12, 2009
ASP.Net UpdatePanel and overriding Page.Render don't mix
I have a website. Well, I have lots of websites but I have one in particularly that has special needs. It needs to be multi-lingual but at the same point it is set up so that translators can change the translations on the fly.
This last point is a killer and renders the conventional ASP.Net localization mechanism null and void. ASP.Net uses resource files for localization. If a translator changes some text, they won't see the change until you rebuild the files for that language. And when you do that, the entire site gets recycled. For everyone. Ick.
Anyway... long story short. I implemented what seemed like a good idea at the time. Whenever there was a block of text I had my controls simply render out text placeholder. For example, $$TextID:123$$. I was then intercepting the Page.Render event and RegEx matching all of these placeholders, building a list of all text IDs to look up, and then doing a single database call to get the results back, then modifying the output on the way through.
At first, all seemed good, but two issues arose.
The first of them is a /facepalm of my own, which is that the approach only works when no post-processing is required on the text. For example, if I was pulling out text that used a wiki markup and I needed to translate that to HTML, it was going to try to interpret $$TextID:123$$ as wiki markup when the control was rendered, and then wasn't going to apply the markup formatting in the Page.Render unless I built something a bit more intelligent.
Fair enough, but doable. But in the end I'm rolling back the approach entirely because, as it turns out, overring Page.Render really borks up the AJAX UpdatePanel.
Now let's be fair: the UpdatePanel is actually a very blunt instrument - too blunt, really - and should be avoided if a more targetted solution can be obtained. If all you're doing is updating HTML text for example, for heaven's sake use web services consumed by the client - they have so much less overhead that UpdatePanels and don't required an entire page postback just to change one bit of text.
However, sometimes you already have UpdatePanels there and sometimes you just need something quick and dirty.
But...
Try the following code on the Render method and check out the result when it's an UpdatePanel postback.
...and check out the value of sTxt
Normally you'll see your page in all its full HTML glory, but in an UpdatePanel postback, you get a completely different kind of markup. Something containing lines like this:
That's only part of it, but it gives you the idea. Now, here's the important bit: those numbers in the pipelines (|5| and |90| for example) actually contain the LENGTH of the text parameter to follow (the "null;" shortly after the |5| is 5 chars long, for example).
So, if you take your rendered output and change "$$TextID:123$$" to "I am a telephone pole" then your client page is not going to interpret the result correctly any more (unless all of your strings happen to be exactly the same length as the ID placeholders).
On its own, this is not insurmountable, but it's a pain for a number of reasons:
But the lesson that I've learnt today is: never override Page.Render to tweak the output OR never use an AJAX UpdatePanel, as the two aren't talking to each other right now. Personally, I think that the UpdatePanel is the one to chuck, but that can be tricksy if you've already got it in there somewhere.
This last point is a killer and renders the conventional ASP.Net localization mechanism null and void. ASP.Net uses resource files for localization. If a translator changes some text, they won't see the change until you rebuild the files for that language. And when you do that, the entire site gets recycled. For everyone. Ick.
Anyway... long story short. I implemented what seemed like a good idea at the time. Whenever there was a block of text I had my controls simply render out text placeholder. For example, $$TextID:123$$. I was then intercepting the Page.Render event and RegEx matching all of these placeholders, building a list of all text IDs to look up, and then doing a single database call to get the results back, then modifying the output on the way through.
At first, all seemed good, but two issues arose.
The first of them is a /facepalm of my own, which is that the approach only works when no post-processing is required on the text. For example, if I was pulling out text that used a wiki markup and I needed to translate that to HTML, it was going to try to interpret $$TextID:123$$ as wiki markup when the control was rendered, and then wasn't going to apply the markup formatting in the Page.Render unless I built something a bit more intelligent.
Fair enough, but doable. But in the end I'm rolling back the approach entirely because, as it turns out, overring Page.Render really borks up the AJAX UpdatePanel.
Now let's be fair: the UpdatePanel is actually a very blunt instrument - too blunt, really - and should be avoided if a more targetted solution can be obtained. If all you're doing is updating HTML text for example, for heaven's sake use web services consumed by the client - they have so much less overhead that UpdatePanels and don't required an entire page postback just to change one bit of text.
However, sometimes you already have UpdatePanels there and sometimes you just need something quick and dirty.
But...
Try the following code on the Render method and check out the result when it's an UpdatePanel postback.
protected override void Render(HtmlTextWriter writer)
{
using (System.IO.MemoryStream msOur = new System.IO.MemoryStream())
using (System.IO.StreamWriter swOur = new System.IO.StreamWriter(msOur))
{
HtmlTextWriter ourWriter = new HtmlTextWriter(swOur);
base.Render(ourWriter);
ourWriter.Flush();
msOur.Position = 0;
using (System.IO.StreamReader oReader = new System.IO.StreamReader(msOur))
{
string sTxt = oReader.ReadToEnd();
}
}
}
...and check out the value of sTxt
Normally you'll see your page in all its full HTML glory, but in an UpdatePanel postback, you get a completely different kind of markup. Something containing lines like this:
|5|onSubmit||null;|90|onSubmit||if (typeof(ValidatorOnSubmit) == "function" && ValidatorOnSubmit() == false) return false;|
That's only part of it, but it gives you the idea. Now, here's the important bit: those numbers in the pipelines (|5| and |90| for example) actually contain the LENGTH of the text parameter to follow (the "null;" shortly after the |5| is 5 chars long, for example).
So, if you take your rendered output and change "$$TextID:123$$" to "I am a telephone pole" then your client page is not going to interpret the result correctly any more (unless all of your strings happen to be exactly the same length as the ID placeholders).
On its own, this is not insurmountable, but it's a pain for a number of reasons:
- If the AJAX team had chosen XML for communicating the UpdatePanel changes to the client, it would have been much easier to overcome this: by simply parsing the XML using the built-in parsers and changing the value of a given length field. Without XML, there's much heavier parsing work required. There may well be good reason why they didn't use XML - I'm not saying it was a wrong decision, I'm just lamenting it...
- It's also a pity that the formatting that they do - where they take the page's HTML and convert it to this pseudocode - seems to be somehow happening internally WITHIN the default Page.Render method. It would be nice if this conversion happened AFTER the Page.Render method so that we could intercept it. What we want to do is to get an override in between the point when the full HTML is generated and when AJAX strips out all the stuff that it doesn't need to send back to the client and creates pseudo-code out of what it does. But because that seems to happen inside Page.Render, I'm not sure it's possible.
- Finally, in conjunction with the formatting issue I mentioned at the very beginning, I think I'm going to file this approach in the "not worth it" basket. A nice idea, but I think there are better ways to optimize.
But the lesson that I've learnt today is: never override Page.Render to tweak the output OR never use an AJAX UpdatePanel, as the two aren't talking to each other right now. Personally, I think that the UpdatePanel is the one to chuck, but that can be tricksy if you've already got it in there somewhere.
Thursday, February 26, 2009
Serving File to User - Frustration!!
For several years now I've had a neat little ASP.Net method which simply serves up a file to the end user. It sets all the headers so that the user is prompted to save or open the file, and handles large files and so on. No trouble.
Today, there was trouble.
I had an application where Internet Explorer, upon having the file served to it, opened the file contents in the browser instead of asking how to handle it. It was a PDF and the raw contents of the PDF were appearing.
It wasn't happening under Firefox or Chrome, but was consistently happening under IE.
Over an exceedingly frustrating day, I tried very many things. I tried using Release mode instead of Debug, in case Debug was adding something to the Headers that was causing grief. I tried cache-busting. I tried running the page in a full window as opposed to the pop-up that it was intended to be in... all to no avail.
In the end, the solution was straightforward but a little surprising. The page in question contained some JavaScript which initiated AJAX calls - basically to monitor if the file was ready to be downloaded or not, and to giving a constantly updating ETA. When the file was being served by ASP.Net, the code ended with a Response.End - which I mistakenly assumed that the rest of the page wasn't rendered.
However, when I put the JavaScript into a MultiView and ensured that it was only displayed if we WEREN'T serving the file, it all suddenly worked.
So... if you are serving a file, make sure that your page doesn't output any javascript. I assumed the Render would be bypassed after the Response.End but... mistaken was I.
Today, there was trouble.
I had an application where Internet Explorer, upon having the file served to it, opened the file contents in the browser instead of asking how to handle it. It was a PDF and the raw contents of the PDF were appearing.
It wasn't happening under Firefox or Chrome, but was consistently happening under IE.
Over an exceedingly frustrating day, I tried very many things. I tried using Release mode instead of Debug, in case Debug was adding something to the Headers that was causing grief. I tried cache-busting. I tried running the page in a full window as opposed to the pop-up that it was intended to be in... all to no avail.
In the end, the solution was straightforward but a little surprising. The page in question contained some JavaScript which initiated AJAX calls - basically to monitor if the file was ready to be downloaded or not, and to giving a constantly updating ETA. When the file was being served by ASP.Net, the code ended with a Response.End - which I mistakenly assumed that the rest of the page wasn't rendered.
However, when I put the JavaScript into a MultiView and ensured that it was only displayed if we WEREN'T serving the file, it all suddenly worked.
So... if you are serving a file, make sure that your page doesn't output any javascript. I assumed the Render would be bypassed after the Response.End but... mistaken was I.
Tuesday, February 24, 2009
HyperLinkField doesn't like mailto
Just came across a "feature" of ASP.Net's GridView which I hadn't hit before.
If you have a HyperLinkField and point the DataNavigateUrlFields to a property or field that returns "mailto:x@y.com", it doesn't work. The entire link gets short circuited and only the text returns.
Apparently this is for security purposes, although it would be nice to be able to override it, EnableEventValidation-style (who knows - maybe you can and I've missed it...)
I thought you might be able to use BoundField, but it turns out that it HtmlEncodes everything, so it looks like a template is the one way to go...
If you have a HyperLinkField and point the DataNavigateUrlFields to a property or field that returns "mailto:x@y.com", it doesn't work. The entire link gets short circuited and only the text returns.
Apparently this is for security purposes, although it would be nice to be able to override it, EnableEventValidation-style (who knows - maybe you can and I've missed it...)
I thought you might be able to use BoundField, but it turns out that it HtmlEncodes everything, so it looks like a template is the one way to go...
Friday, February 20, 2009
Code Documentation in Visual Basic .NET 2008
In Visual Studio 2008, Visual Basic finally inherited code documentation shortcuts. This is simply the very convenient mechanism by which typing 3 apostrophes on the line before a method declaration or similar will automatically resolve through intellisene or macroing or some kind of magic woven by the IDE pixies into a template for entering the documentation for that method.
For example:
''' <summary>
''' </summary>
''' <param name="id"></param>
''' <returns></returns>
''' <remarks></remarks>
Great stuff! As long as it's enabled. I had two projects in the one solution where typing ''' resolved into a documentor template as above for one of the projects, but merely sat there gathering dust in the other.
After spending more time than I care to admit trying to figure out what IDE settings option I needed to change in order to enable it, or even what library I needed to import in order to get it to work (yes, I was getting desperate and trying everything...) I found the solution, which in the end makes some sense but is definately lateral as an answer to this particular question.
I'd check the Project settings, but none of them were editor-related: they all seemed compile-related. Which they are. But it turns out that if you don't have "Generate XML document file" ticked in your Visual Basic project, the IDE won't offer up XML documentation comments to you.
For example:
''' <summary>
''' </summary>
''' <param name="id"></param>
''' <returns></returns>
''' <remarks></remarks>
Great stuff! As long as it's enabled. I had two projects in the one solution where typing ''' resolved into a documentor template as above for one of the projects, but merely sat there gathering dust in the other.
After spending more time than I care to admit trying to figure out what IDE settings option I needed to change in order to enable it, or even what library I needed to import in order to get it to work (yes, I was getting desperate and trying everything...) I found the solution, which in the end makes some sense but is definately lateral as an answer to this particular question.
I'd check the Project settings, but none of them were editor-related: they all seemed compile-related. Which they are. But it turns out that if you don't have "Generate XML document file" ticked in your Visual Basic project, the IDE won't offer up XML documentation comments to you.
Thursday, February 19, 2009
IIS Processes that Bloat
One of the peskiest problems in maintaining a web server is IIS processes that bloat. The whole server runs like a dog and when you check the Task Manager, you find that one service is taking up 80% of the CPU cycles and half a GB of RAM...
You have the PID of the process through Task Manager, but I used to have difficulty nailing down which process was causing the problem from there.
The simple trick is to run the command line command iisapp. This script simply lists all running application pools and their PIDs. It lets you pick the faulty PID straight away (as long as you can remember the name of the command...)
You have the PID of the process through Task Manager, but I used to have difficulty nailing down which process was causing the problem from there.
The simple trick is to run the command line command iisapp. This script simply lists all running application pools and their PIDs. It lets you pick the faulty PID straight away (as long as you can remember the name of the command...)
Subscribe to:
Posts (Atom)