Issue running ASPX page using Scheduled Task - asp.net

I have a scheduled task set up to run Scan.aspx every 3 minutes in IE7. Scan.aspx reads data from 10 files in sequence. These files are constantly being updated. The values from the file are inserted into a database.
Sporadically, the value being read is truncated or distorted. For example, if the value in the file was "Hello World", random entries such as "Hello W", "Hel", etc. will be in the database. The timestamps on these entries appear completely random. Sometimes at 1:00 am, sometimes at 3:30 am. And some nights, this doesn't occur at all.
I'm unable to reproduce this issue when I debug the code. So I know under "normal" circumstances, the code executes correctly.
UPDATE:
Here is the aspx codebehind (in Page_Load) to read a text file (this is called for each of the 10 text files):
Dim filename As String = location
If File.Exists(filename) Then
Using MyParser As New FileIO.TextFieldParser(filename)
MyParser.TextFieldType = FileIO.FieldType.Delimited
MyParser.SetDelimiters("~")
Dim currentrow As String()
Dim valueA, valueB As String
While Not MyParser.EndOfData
Try
currentrow = MyParser.ReadFields()
valueA= currentrow(0).ToUpper
valueB = currentrow(1).ToUpper
//insert values as record into DB if does not exist already
Catch ex As Exception
End Try
End While
End Using
End If
Any ideas why this might cause issues when running multiple times throughout the day (via scheduled task)?

First implement a Logger such as Log4Net in your ASP.NET solution and Log method entry and exit points in your Scan.aspx as well as your method for updating the DB. There is a chance this may provide some hint of what is going on. You should also check the System Event Log to see if any other event is associated with your failed DB entries.
ASP.NET is not the best thing for this scenario especially when paired with a Windows scheduled task; this is not a robust design. A more robust system would run on a timer inside a Windows-Service-Application. Your code for reading the files and updating to the DB could be ported across. If you have access to the server and can install a Windows Service, make sure you also add Logging to the Windows Service too!
Make sure you read the How to Debug below
Windows Service Applications intro on MSDN: has further links to:
How to: Create Windows Services
How to: Install and Uninstall Services
How to: Start Services
How to: Debug Windows Service Applications]
Walkthrough: Creating a Windows Service
Application in the Component Designer
How to: Add Installers to Your Service Application
Regarding your follow up comment about the apparent random entries that sometimes occur at 1am and 3.30am: you should:
Investigate the IIS Log for the site when these occur and find out what hit(visited) the page at that time.
Check if there is an indexing service on the server which is visiting your aspx page.
Check if Anti-Virus software is installed and ascertain if this is visiting your aspx page or impacting the Asp.Net cache; this can cause compilation issues such as file-locks on the aspnet page in the aspnet cache; (a scenario for aspnet websites as opposed to aspnet web applications) which could give weird behavior.
Find out if the truncated entries coincide with the time that the files are updated: cross reference your db entries timestamp or logger timestamp with the time the files are updated.
Update your logger to log the entire contents of the file being read to verify you've not got a 'junk-in > junk-out' scenario. Be careful with diskspace on the server by running this for one night.
Find out when the App-Pool that your web app runs under is recycled and cross reference this with the time of your truncated entries; you can do this with web.config only via ASP.NET Health Monitoring.
Your code is written with a 'try catch' that will bury errors. If you are not going to do something useful with your caught error then do not catch it. Handle your edge cases in code, not a try catch.
See this try-catch question on this site.

Related

Start Process from .NET Web Application with Impersonalisation

I try to call an .exe file from a webapplication.
But I want the file called by the user that is impersonalisated by windoes authentication from the website.
Process process = new Process();
try
{
process.StartInfo.UseShellExecute = false;
process.StartInfo.FileName = ConfigData.PVDToBudgetDBexePath;
process.StartInfo.CreateNoWindow = false;
process.Start();
log.Info("Process started by " + WindowsIdentity.GetCurrent().Name + " with ID: " + process.Id);
process.WaitForExit();
log.Info("After WaitForExit Process ID: " + process.Id);
}
catch (Exception ex)
{
log.Error("Error executing file with message " + ex.Message);
}
Both info log texts are logged correctly. There is no error occuring.
But the called Program does not do anything. No logging, no writing in Database.
The user has executable rights on the file.
When I call the same Code from Development Server it works fine.
I use .Net 4.5 and IIS 7
I found posts concerning this topic only for very old versions of .Net and IIS and that could not help me.
What am i doing wrong?
Or how can I find out whats going wrong?
many thanks,
EDIT:
To better make clear what I intend:
I have this (self made) exe file that imports Data from Excel Sheets into a Database. That needs some time. While doing this it logs its Progress whith log4net also into the database.
I want an UI (web application) were the user can trigger the import.
on this UI there is also an ajax progressbar that shows the progress of the import takten from the log table in the database.
I want maximum one instance of this import process to run in the same time. So I have a function that checks wheter the process is still running.
If so it does not allow to start another process. If not you can start it again.
private bool IsRunning(string name)
{
Process[] processlist = Process.GetProcesses();
if (Process.GetProcessesByName(name).Length > 0 )
{
return true;
}
else
{
return false;
}
}
I solved the problem now by starting the exe file via TimeScheduler.
path = filepath to the exe file
arguments = arguments to start the exe file with
using Microsoft.Win32.TaskScheduler;
using (TaskService taskService = new TaskService())
{
var taskDefinition = taskService.NewTask();
taskDefinition.RegistrationInfo.Author = WindowsIdentity.GetCurrent().Name;
taskDefinition.RegistrationInfo.Description = "Runs exe file";
var action = new ExecAction(path, arguments);
taskDefinition.Actions.Add(action);
taskService.RootFolder.RegisterTaskDefinition("NameOfTask", taskDefinition);
//get task:
var task = taskService.RootFolder.GetTasks().Where(a => a.Name == "NameOfTask").FirstOrDefault();
try
{
task.Run();
}
catch (Exception ex)
{
log.Error("Error starting task in TaskScheduler with message: " + ex.Message);
}
}
If you mean by development server the web server that is launched by Visual Studio, than this gives you a false test case since that server is launched by Visual Studio and uses your Windows account to run, while a standard configured IIS does not run under a "user" account but a very limited system account (luckily !!). Even if the user is logged in with a domain account in your website, the IIS process will not run under this account (that wouldn't make sense anyway). That is the reason why this code will not run in IIS and will run in your development server. Even if you get the exe to launch, it will run using the system account of IIS since you didn't supply any account, which is a limited account which will again run the exe different than you expected.
You will have to use impersonation, if you really want to go this way, but you will have to launch that process "impersonating" the user that is logged in in the website, asuuming that user account used to login even makes sense at that point. E.g. if it is a domain account, this might work, but if you use some other kind of authentication, like forms authentication, this has no meaning on OS level and thus you cannot use those credentials for impersonation in IIS.
In my experience, and I have done this a few times, impersonation in IIS is always a bad thing and is always creating issues, the same goes for launching command line process by the way.Luckily there is always a better/alternative solution when you think about it. Also the wait for a process to end in your code is not really a good practice. What if the process blocks? It will block website.
Luckily there is always a better/alternative solution when you think about it. A better/possible solution here is to use message queuing for example, where you just push a message to execute the task, and on the other end an application which processes the messages, which might use this command line tool then. That application can run under any user account you want, without you having to let IIS run under a different account. Later on you must of course come back to find the result of the operation, but that can be done using a callback in the background of your website. though this solution is a little bigger than what you are trying to do, it will have a better result on almost every field (responsiveness of your site, maintainability, scalability,..) the only thing where it is worse is the lines of code that you will need, but that is seldomly a valid factor to take into account
If you write the appplication for excel processing yourself, you can use a table in the DB as some kind of queue instead of using a message bus. Your web application then just needs to add rows with all necesarry info for the process in that table, the status and progress being one of them. Extend your processing application to monitor this table continuously and as soon as it detects a new record, it can then start to do the necessary task and update the db accordingly progress and status and end result). This avoids the messaging sub-system, will work equally good and will avoid you to have to launch a process with impersonation, which was the evil thing to start with.
You can modify the excel process to a windows service so that it runs continuously and starts with the system, but, if you don't want to, there are also tools to run any command line application as a windows service).
This technique would be much easier than the impersonation and allows your website to run in it's protected environment

Rare System.NullReferenceException show up for a HttpContext.Current.Session["courseNameAssociatedWithLoggedInUser"] that was previously populated?

Our ASP.NET C# web application is used in the following environment
.NET Framework 4
Silverlight 4 / PivotViewer
IIS 7
Windows 2008
Visual Studio 2010 .NET IDE
C#
HTTPS ( SSL )
Our Silverlight 4 / PivotViewer controls are obviously embedded in
ASP.NET pages.
In rare cases we get the "Object reference not set to an instance of
an object. error when navigating around ASP.NET pages that host our
Silverlight 4 / PivotViewer modules on our standalone Windows 2008
server with IIS 7.
Also, there is number of very odd things about the error. First, it
occurs only sometimes on certain user computers. To elaborate, it
usually only occurs when a the user uses a computer that accesses our ASP.NET web application for the first time.
Moreover, once we clear the browser cache the error does Not occur
when navigating around ASP.NET pages that host our
Silverlight 4 / PivotViewer modules.
Another interesting aspect about the error is that it refers to
absolute path on my local development computer in the error stack
trace when it is in reality deployed to the standalone Windows 2008
server with IIS 7. That`s really strange because before I deploy to
the standalone Windows 2008 server with IIS 7, I ensure that all
configuration parameters in files such as web.config refer to the
standalone server environment. In other words, I remove any
references to configuration parameter values associated with my local
development computer.
Therefore, I am confused as to why it refers to absolute path on my
local development computer in the error stack trace.
It would be bad experience for the user to get the "Object reference
not set to an instance of an object.` while using the site. Also, it
would be bad user experience if we have to tell the user to clear
his/her browser cache everytime the error shows up.
Server Error in '/' Application.
Object reference not set to an instance of an object.
Description: An unhandled exception occurred during the execution of
the current web request. Please review the stack trace for more
information about the error and where it originated in the code.
Exception Details: System.NullReferenceException: Object reference not
set to an instance of an object.
Source Error:
An unhandled exception was generated during the execution of the
current web request. Information regarding the origin and location of
the exception can be identified using the exception stack trace below.
Stack Trace:
[NullReferenceException: Object reference not set to an instance of an object.]
PivotServer.SectionBasedRelatedModules.SectionBasedPerlsViewer.tailorConfigurationDetailsOfPageElementsToFallInLineWithTutorialSelection()
in C:\VisualStudioWorkSpace\VisualCSharpProjects\PerlsPivot\PivotServer\SectionBasedRelatedModules\SectionBasedPerlsViewer.aspx.cs:160
PivotServer.SectionBasedRelatedModules.SectionBasedPerlsViewer.Page_Load(Object
sender, EventArgs e) in
C:\VisualStudioWorkSpace\VisualCSharpProjects\PerlsPivot\PivotServer\SectionBasedRelatedModules\SectionBasedPerlsViewer.aspx.cs:146
System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp,
Object o, Object t, EventArgs e) +24
System.Web.UI.Control.LoadRecursive() +70
System.Web.UI.Page.ProcessRequestMain(Boolean
includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
+3063
Version Information: Microsoft .NET Framework Version:4.0.30319;
ASP.NET Version:4.0.30319.272
I looked at line 160 which contains the following code:
String coursename = HttpContext.Current.Session["courseNameAssociatedWithLoggedInUser"].ToString();
Obviously, this tells us that there is no value for the variable "courseNameAssociatedWithLoggedInUser" in the HttpContext.Current.Session.
However, I took the same steps on another computer but it all ran smoothly.
Also, I am sure that I am giving a value to the HttpContext.Current.Session["courseNameAssociatedWithLoggedInUser"] as soon as the user logs in.
Does the HttpContext.Current.Session["courseNameAssociatedWithLoggedInUser"] get corrupted for some reason? If so, why, and how do we prevent it?
Should I be using Page.Session instead of HttpContext.Current.Session? Would that help?
"Obviously, this tells us that there is no value for the variable"courseNameAssociatedWithLoggedInUser" in the
HttpContext.Current.Session."
Not exactly... given your code...
String coursename = HttpContext.Current.Session["courseNameAssociatedWithLoggedInUser"].ToString();
... the following items could be causing this
HttpContext - unlikely
HttpContext.Current - more often than you would think, but would be reproducible
HttpContext.Current.Session["courseNameAssociatedWithLoggedInUser"]
To find out the specific item in that chain, you could do something like this (pseudo code)
function string GetCourseNameThingie()
{
if HttpContext is null
throw new Exception("HttpContext is null")
if HttpContext.Current is null
throw new Exception("HttpContext.Current is null")
if HttpContext.Current.Session["courseNameAssociatedWithLoggedInUser"] is null
throw new Exception("HttpContext.Current.Session["courseNameAssociatedWithLoggedInUser"]is null")
return HttpContext.Current.Session["courseNameAssociatedWithLoggedInUser"].ToString()
}
This would tell you specifically what was missing. As we have pointed out, it is more likely the value is either being cleared by another page or an error is occurring that is severe enough to destroy session for that user (Do you have a Application_Error or Session_End handler in Global.asax?).
You can also try wrapping the original statement in a try/catch and if an exception occurs, immediately check another session variable you assume to be still working. This will also tell you for sure whether the other variables are OK or not.
First, sorry for my grammar-English.
I had a similar issue with my .net applications and the reason was the idle time expiration.
There are four time expiration settings "(Yes 4)" and the recycling process of the application pools. I did the following
A) From Application pool: Open the advance setting and change the "Idle Time out". By default is 20 minutes.
Also, set the "Regular Time Interval" to 0. so it wont be recycled. I do not know why microsoft decided to default this to 1740 minutes. This is not a time out setting, it is a setting for always recycling the appPool after a period of time, so if your users are in the middle of something they will loose everything or having exceptions like that one you are having. Setting it to 0 will disable this.
B) Authentication Time Out. if you are using it, for example Form Authentication, then go to the authentication feature of your virtual directory app, right click in "Form Authentication" and select "Edit". Change the authentication cookie-time out.
C) ASP.NET Session State. in ISS, open the .net session state feature and change the session time-out. It is also by default 20 minutes.
D) asp.net form authentication time out. This was confusing for me at the beginning because I had already modified the cookie-time out of the form authentication in IIS (Step B). So I still had some problems, when I realised that I also need to change the web.config form authentication tag in order to add a time out attribute for changing the default 20 minutes.
My tag is looking like that: ...forms name=".ASPXFORMSAUTH" path="/" loginUrl="frmLogin.aspx" timeout="1740" protection="All" ...
We have developed a javascript mechanism that take the session state time out setting so we warm users that the system is about to auto log off due to inactivity.
It works beautiful now, Basically I have set all the time out settings to "1740" minutes, except the session state that we set to 30 minutes. So at the minute 29 of inactivity we show the user that the system will auto log off in a minute unless that they do some activity so the idle time is beginning from 0 again. Brilliant, now we do not have any problem with sessions.
Anyway guys, I have told you our experience and how we solve a similar problem that you are having now. However, the reason why I ended here is because we also want to eliminate the references to the absolute path on my local development computer at the moment of any exception.
We have not figured out why it is showing the absolute path. We have compiled our DLL assemblies in released mode, but this does not change anything. Have someone of you sort it out this issue?????
Thanks guys
Referencing a Session Within a ViewModel
You may not be using ASP.net MVC, but this would be useful if someone were to be looking for an answer.
I was in exactly the same situation except I would receive the null exception every time, whereas my colleague didn't at all, even though we were running exactly the same code.
Our mistake was to reference a session variable from a ViewModel, which is apparently bad practice. The code was changed so that the ViewModel received the session contents via the controller then set it as a property of the ViewModel. The session data (my example is called ProcessingWeek) would use this.ProcessingWeek, and not look directly at the httpcontext.current.session["ProcessingWeek"].
EventMatchResult Match = new EventMatchResult(
(ImportedEventModel)SessionData.ImportedEventModel,
ref db,
SessionData.ProcessingWeek);
...
public EventMatchResult(ImportedEventModel Event, ref CFModel db,
int ProcessingWeek)
{
this.db = db;
this.MatchedField = new List<PlayerMatchResult>();
this.ImportedEvent = Event;
this.ProcessingWeek = ProcessingWeek;
}

Is it possible to persist WebTestContext across ASP.NET load test session?

I want to load test an enterprise Web application (which I did not build), using a Visual Studio 2010 Ultimate Load Test. I want each virtual user to log in at the beginning, and log out at the end of their run of random tests. I can properly configured the load test to do so. However, there is a complication. The session key is injected into the URL, like this:
http://ProductName/(S(ilv3lp2yhbqdyr2tbcj5mout))/System/Container.aspx
I converted the Visual Studio WebTests to coded tests, and then retrofit them with code that uses the session-specific URL. This works fine. What I need to do is persist this session encoded URL across the various tests that specific virtual user runs, starting with the login WebTest class, to the logout WebTest class.
The individual WebTest classes are capable of logging in and out at the beginning and end of each test. However, this is not an accurate representation of normal use. This application emulates a mainframe terminal, and never cuts the connection or session between Web browser requests. Each session is one long, interactive HTTP request, just like a mainframe terminal interacts with, for example, an IBM AS400. Usert typically log in to the mainframe at the beginning of day, and (should) log out at the end of day. Likewise, this Web application maintains the HTTP request until the user logs out, or the IIS session timeout occurs. Therefore, it is important I keep the same session in the URL, between all tests, to ensure memory leaks and other nasty bugs don't accumulating.
Please share your thoughts!
Problem 1: persist the session id across test iterations
You can store data in the 'user context' which is persistent across test iterations. It is found in the WebTestContext having the name '$LoadTestUserContext'. (But note that this context parameter only appears in load test runs, not in standalone web test runs)
// within WebTestPlugin.PreRequest() or MyExtractionRule.Extract()
// e is the corresponding eventargs object...
LoadTestUserContext userContext = (LoadTestUserContext)e.WebTest.Context["$LoadTestUserContext"];
...
// setting the value in the user context (i.e. in the extraction rule)
userContext["sessionId"] = "(extracted session id)";
...
// getting the value from the user context (i.e. in WebTestPlugin PreWebTest event)
e.WebTest.Context["sessionId"] = userContext["sessionId"];
You'll have to add a WebTestPlugin (that fetches the value from the user context into the web test context) to all of your web tests to make the value available across all tests.
Problem 2: Login/Logout only at start and end of load test
extract the login and logout functionality into their own separate tests (remember that the logout test also needs the WebTestPlugin that fetches the stored sessionId)
in the Load Test, the Edit Test Mix dialog lets you specify an Initialize and Terminate test: set these to the Login and Logout tests you just created
in the Load Test Scenario, set "Percentage of New Users" to 0.
Some additional explanation of the "Percentage of New Users" setting
The "Percentage of New Users" setting is poorly named and does not indicate its full behaviour.
When a "New User" starts a test iteration, it takes a new $WebTestUserId (and gets a new fresh user context, which you don't want)
When a non-"New User" starts a test iteration, it keeps the same old $WebTestUserId (and the old user context, which you do want)
So far so good. But the unexpected part is this:
Each "New User" executes the following during a load test:
Initialize > web test iteration > Terminate
A non-"New User" executes the following for the entire duration of the load test:
Initialize > iteration1 > iteration2 > ... > iterationN > Terminate
In other words, "New Users" are constantly logging in and out (which you don't want). Non-"New Users" only login and logout once in the entire load test, and continually run test iterations for the duration (which you do want).

What Tool or Script Can I Use to Find Which Directory Is Invalid When Receiving a "The directory name is invalid" error in IIS 7?

The Goal
I would like only a certain group of users (who are in an Active Directory group composed of users from two domains) to be able to execute a web script, in http://www.site.org/protected, after being challenged for authentication.
The Setup
Windows 2008, IIS 7. User Account Access has been disabled, as it is a pain and sometimes causes perfectly reasonable things to fail. The server is part of a domain I will called LITTLEDOMAIN. We have a trust with BIGDOMAIN.
I have a group, called "LITTLEDOMAIN\can-use-this." In that group are the members LITTLEDOMAIN\me and BIGDOMAIN\me. I did the bit in Active Directory where the server now allows that group to authenticate against another domain (BIGDOMAIN).
The application pool for www.site.org runs as "NetworkService."
The dirctory has the user SYSTEM, the user NETWORK SERVICE, the group Enterprise Admins, and the group LITTLEDOMAIN\can-use-this with at least Read and Execute permissions.
In IIS 7, I have disabled all forms of authentication for that directory but Windows Authentication. As to Authorization Rules, All Users are Allowed.
The Error
When I use, say, FireFox, visit the URL http://www.site.org/protected, and am presented with a challenge, I can enter the username LITTLEDOMAIN\me and my password, then see the minimal HTML generated by my very simple Python script, which is basically a "Hello, World" with a timestamp thrown in so I can make sure caching of the page does not occur. If I use BIGDOMAIN\me, I receive an HTTP 500 error.
Diagnostics Performed
The passwords for LITTLEDOMAIN\me and BIGDOMAIN\me are the same; this has been checked.
I look in the HTTP logs and see the "500 0 267" for "sc-status sc-substatus sc-win32-status" in the HTTP logs. A "net helpmsg 267" from the command line gives me "The directory name is invalid."
I added Failed Request Tracing Rules and see the same unhelpful message in the XML: "The directory name is invalid. (0x8007010b)"
I have turned on file object auditing in the policy for that server, then set the auditing for the directory and the files within it to have all failures for "Everyone," but nothing shows up in the Security section of Event Viewer. I was able to cause other failures, so I know that failure auditing is working. This suggests that the system is not even getting to the point where the file is being accessed.
I gave, temporarily, the group LITTLEDOMAIN\can-use-this full control over the C:\TEMP directory, on the off chance this was in use. I recycled the application pool. The same error occurs. I tried this in C:\Windows\Temp as well, to no avail.
The Question
How can I find out "well, WHICH directory name is invalid?" It's pretty obvious that something, somewhere along the line, wants permissions for BIGDOMAIN, but I cannot figure out where.
The missing component, in addition to an audit policy and Failed Request Tracing, is Process Monitor. Not Process Explorer, but Process Monitor.
Run Process Monitor for three or so seconds, just long enough to get your request in, and have it fail. Use Failed Request Tracing to get the process ID that failed. Use Process Monitor's filter to show only events where the process ID appears -- you can then see where it fails.
Then set auditing on that directory to see what account is being used.
It appears that IIS 7 is returning to the root of the webserver when looking at a protected subdirectory. Odd.

Error Log information in VB Script while processing

I am having an VBScript files which runs by many instance of jobs. I need to log the error information if any error occurs in the script processing. If i maintain a log file then how can i differentiate the log file for each instances (around 10 simultaneous instances) of vb script calling.
I dont go for any db logging.
Please suggest some good ways.
I would use the same log file for all instances. I would then have each instance create a GUID:
http://www.microsoft.com/technet/scriptcenter/resources/qanda/feb05/hey0221.mspx
When an error is logged by an instance, it uses the GUID to identify itself. This way it shouldn't matter if you have 10 or 50 instances, they will be unique in logging and you won't have a ton of log files everywhere.

Resources