Puzzling differences in behavior between console and web apps - c#

I have a piece of code in a Web API app:
private Stream ConvertWorkBookToStream(WorkBook workBook)
{
var tempFileName = Path.GetTempFileName();
// The following line throws a NullReferenceException
workBook.write(tempFileName);
// Remainder elided for brevity
}
Neither workBook nor tempFileName are null.
On a whim, I changed the app pool to run under a domain administrator account, to eliminate any permissions issues (since I've observed some general wonkiness on my machine of late) and re-ran it. The same exception was thrown.
Then I created a console application and copied the method, verbatim, into the app and ran it. No exception was thrown.
Now, it bears noting that just yesterday, I ran into a similar puzzling behavior regarding File.Exists.
Consider the following call:
var exists = File.Exists(#"\\myshare\\myexistingfile.ext");
Assuming that the path refers to a file that actually exists:
Under a web app, exists returns false on my machine.
The same operation, in a console application, returns true.
My coworkers are experiencing the opposite behaviors.
Can anyone explain this? I'm rather at my wits' end.

Check to see if the return from Path.GetTempFileName is different from the console app and the web app. Windows could be playing tricks with you. I had similar issues attempting to write log files. I just gave up and put them int the same directory as my web service.

In your IIS Authentication settings, are you only having Anonymous Authentication enabled? If I remember correctly Anonymous Authentication impersonates the IUSR account with restricted privileges.

Related

C# The network path was not found

Im having trouble with writing files to remote directory via network. The following code fails when I try to check if the directory exists:
if (!Directory.Exists(processingPath))
Directory.CreateDirectory(processingPath);
processingPath is composed like
processingPath = xxxObject.serverPath + "processing\\";
xxxObject.serverPath contains something like this
\\machineNetworkName\sharedFolder\
Its working properly, but when many requests are processing (running as tasks asynchronously), it stops working and failing into exception:
System.IO.IOException: The network path was not found.
Could you please help me what could be the problem and why it is failing after some time on network path???
Thanks for your solutions
I got the same error before, it was about authentication problems.
You have to be sure that you set properly the user on IIS, because it use a Default App Pool's identity which can't access to your NFS.
You can also use IIS virtual folders to set the identity.
(on IIS manager, see App Pool settings -> Identity and also virtual folders settings -> identity).
In my case, it worked better by using the Impersonation directly in the code, so I recommend you to use the VladL WrappedImpersonationContext Object: How to provide user name and password when connecting to a network share
Last thing to check, the owner of the files on your NFS server, if they were created under the root user, it might not work.
I had the same problem and solved it. The problem in my code and I see it in yours, too, is that you have the slash at the end of the network path.
Instead of processingPath = xxxObject.serverPath + "processing\\"; write: processingPath = xxxObject.serverPath + "processing";

Exception while trying to query IIS from C# service

I'm calling the following code from Windows service that was written with C#:
try
{
ServerManager m = new ServerManager();
if(m != null)
{
SiteCollection sites = m.Sites; //I get exception here
}
}
catch (Exception ex)
{
}
I get this exception:
{"Filename: redirection.config\r\nError: Cannot read configuration
file\r\n\r\n":null}
What does that mean? And is there any way to predict it in ServerManager or my m variable before it's thrown?
Update: After looking at your comment now I can answer the question fully, the problem is your application is referencing the wrong Microsoft.Web.Administration.dll, seeing the error tells me you are referencing the IIS Express version and not the "full" IIS Version (7.0.0.0). So please modify your application code to add a reference to the one that is in c:\windows\system32\inetsrv\Microsoft.Web.Administration.dll instead.
This is a permissions problem.
You will need to make sure to run the Windows Service as an identity that is either a member of the Administrators group or SYSTEM. My guess is you might be running the service as Local Serivce or Network Service and those do not have permission to read the configuration files that sit in %windows%\system32\inetsrv\config.
Other Info:
Redirection.config is a file that IIS uses to determine if it should read its configuration from the normal path (%windir%\system32\inetsrv\config\applicationHost.config) or should read it from say an external UNC file share when centralized configuration is used for many servers. That is why this is one of the first files to be parsed and hence you get that access denied error for that specific file.
Regarding the predicting, the best thing to do would be to create it within a try/catch and handle that. There are many exceptions that could happen when reading configuration, such as permissions (you could predict this one by making sure you can read (say File.OpenText()) to Redirection.config, ApplicationHost.config in %windir%\system32\inetsrv\config but that is guessing and there are others such as access to encryption keys for passwords, invalid config, etc, etc.)

O365 via PowerShell in ASP.NET MVC 3: MicrosoftOnlineException was thrown

I have an ASP.NET MVC 3 application which uses PowerShell to connect to Office 365 to retrieve some details about user licenses.
The code itself works in many cases:
The project in my local IIS works
A piece of code in LINQPad using the library works on my machine
A piece of code in LINQPad using the library works on the target server
And where it doesn't work is of course the only place it really should work: The IIS on the target server.
I always get an Exception when calling the Connect-MsolService cmdlet. The problem is that the Exception doesn't tell me anything.
The Exception type is
Microsoft.Online.Administration.Automation.MicrosoftOnlineException
and the message is
Exception of type 'Microsoft.Online.Administration.Automation.MicrosoftOnlineException' was thrown
which is pretty useless.
The Office 365 user account I use in my code is always the same. The user account used to start the IIS is always the same, too (Local System).
I wrapped the PowerShell code execution in a class named PowerShellInvoker. Its code can be found here.
And here is the code that connects to Office 365:
var cred = new PSCredential(upn, password);
_psi = new PowerShellInvoker("MSOnline");
_psi.ExecuteCommand("Connect-MsolService", new { Credential = cred });
There is no Exception actually thrown, the error is found in the Error property of the pipeline. (See lines 50ff. of the PowerShellInvoker class.)
The problem is that I don't know what could be wrong, especially because the same code works when I use LINQPad. The search results by Google couldn't help me either.
The server runs on Windows Server 2008 R2 Datacenter SP1 with IIS 7.5.
I found the solution!
I don't know the reason, but on the target server, the app pool's advanced settings for my app had set Load User Profile to False. I changed it back to True (which should be default) and voilĂ , it works!
Edit: The Load User Profile setting was apparently automatically set to False by default because the IIS 6.0 Manager was installed and False was the default behavior until IIS 6.0.

Windows service can't write to %LOCALAPPDATA%

I have built an app that works only when not run as a Windows service. Well, the service runs, but it doesn't do what it should. The service uses the Local Service account. So to kick off debugging, I thought I'd start with something simple: have it create a directory when it starts:
Directory.CreateDirectory(
Environment.SpecialFolder.LocalApplicationData + "\\MyService");
When I started the service, it stopped almost immediately and Windows reported that fact. When I commented out the above statement, recompiled and re-installed, the service ran without stopping.
Obviously the above line throws an exception of some sort. I have no way of logging the error because I can't write to the file system. Any ideas why Local Service can't create a directory in its own %LOCALAPPDATA%?
You should use GetFolderPath with LocalApplicationData like so:
string folderName = Path.Combine(Environment.GetFolderPath(
Environment.SpecialFolder.LocalApplicationData),
"MyService");
Directory.CreateDirectory(folderName)
I think this might be because there is no special folder. When running as the local service account you are running under that user, not the logged in user. so you are requesting a special folder that probably wont exist, as I don't think the local service has a profile. (I may be wrong) - I was wrong :p
Just in case anyone pops by:
C:\Windows\ServiceProfiles\LocalService
is the local service profile folder, so it will end up in there.
If you want to debug it surround that line with a try catch, and then write the error to a file:
try
{
Directory.CreateDirectory(Environment.SpecialFolder.LocalApplicationData + "\\MyService");
}
catch (Exception ex)
{
System.IO.StreamWriter file = new System.IO.StreamWriter(#"C:\MyServicelog.txt",true);
file.WriteLine(ex.Message);
file.Close();
}
At least then you can see whats causing the error
Martyn
I suggest you write the exception details to the event log. All user accounts have permission to write to the event log as long as the log and source names have already been created by an administrator (which you can do simply by running the app as yourself first).
As to the root cause of the error, it may be because LocalService doesn't normally get a full set of profile folders created by default. I'm not sure whether this is by design, or simply what I have observed on various machines.

How to use ServerManager to read IIS sites, not IIS express, from class library OR how do elevated processes handle class libraries?

I have some utility methods that use Microsoft.Web.Administration.ServerManager that I've been having some issues with. Use the following dead simple code for illustration purposes.
using(var mgr = new ServerManager())
{
foreach(var site in mgr.Sites)
{
Console.WriteLine(site.Name);
}
}
If I put that code directly in a console application and run it, it will get and list the IIS express websites. If I run that app from an elevated command prompt, it will list the IIS7 websites. A little inconvenient, but so far so good.
If instead I put that code in a class library that is referenced and called by the console app, it will ALWAYS list the IIS Express sites, even if the console app is elevated.
Google has led me to try the following, with no luck.
//This returns IIS express
var mgr = new ServerManager();
//This returns IIS express
var mgr = ServerManager.OpenRemote(Environment.MachineName);
//This throws an exception
var mgr = new ServerManager(#"%windir%\system32\inetsrv\config\applicationhost.config");
Evidently I've misunderstood something in the way an "elevated" process runs. Shouldn't everything executing in an elevated process, even code from another dll, be run with elevated rights? Evidently not?
Thanks for the help!
Make sure you are adding the reference to the correct Microsoft.Web.Administration, should be v7.0.0.0 that is located under c:\windows\system32\inetsrv\
It looks like you are adding a reference to IIS Express's Microsoft.Web.Administraiton which will give you that behavior
Your question helped me find the answer for PowerShell, so if the Internet is searching for how to do that:
$assembly = [System.Reflection.Assembly]::LoadFrom("$env:systemroot\system32\inetsrv\Microsoft.Web.Administration.dll")
# load IIS express
$iis = new-object Microsoft.Web.Administration.ServerManager
$iis.Sites
# load IIS proper
$iis = new-object Microsoft.Web.Administration.ServerManager "$env:systemroot\system32\inetsrv\config\applicationhost.config"
$iis.Sites
CAUTION! Using this approach we have seen seemingly random issues such as "unsupported operation" exceptions, failure to add/remove HTTPS bindings, failure to start/stop application pools when running in IIS Express, and other problems. It is unknown whether this is due to IIS being generally buggy or due to the unorthodox approach described here. In general, my impression is that all tools for automating IIS (appcmd, Microsoft.Web.Administration, PowerShell, ...) are wonky and unstable, especially across different OS versions. Good testing is (as always) advisable!
EDIT: Please also see the comments on this answer as to why this approach may be unstable.
The regular Microsoft.Web.Administration package installed from NuGet works fine. No need to copy any system DLLs.
The obvious solution from the official documentation also works fine:
ServerManager iisManager = new ServerManager(Environment.SystemDirectory + #"inetsrv\config\applicationHost.config");
This works even if you execute the above from within the application pool of IIS Express. You will still see the configuration of the "real" IIS. You will even be able to add new sites, as long as your application runs as a user with permission to do so.
Note, however that the constructor above is documented as "Microsoft internal use only":
https://msdn.microsoft.com/en-us/library/ms617371(v=vs.90).aspx
var iisManager = new ServerManager(Environment.SystemDirectory + "\\inetsrv\\config\\applicationhost.config");
This works perfectly. No need to change any references

Categories

Resources