i' m developing webapp in ASP.NET 2.0 (C#). I've problem to resolve issue.
The application should show users on-line, and only for administrator should show the user name. I'm using Application[] object to store usermame and count, setting the value in Globall.asax file.
In the following code i'll show the section relative to counter:
protected void Application_Start(object sender, EventArgs e){
Application["OnlineCounter"] = 0;
}
protected void Session_Start(Object sender, EventArgs e){
// Code that runs when a new session is started
if (Application["OnlineCounter"] != null){
Application.Lock();
Application["OnlineCounter"] = ((int)Application["OnlineCounter"]) + 1;
Application.UnLock();
}
}
protected void Session_End(Object sender, EventArgs e){
// Code that runs when a new session is started
if (Application["OnlineCounter"] != null){
Application.Lock();
Application["OnlineCounter"] = ((int)Application["OnlineCounter"]) - 1;
Application.UnLock();
}
}
Using this code on my local machine i can count correctly the online user.
Instead, when i publish this code on server (Windows 2003 Server and IIS6) i found the following problem:
accessing from my machine with 3 different user (using different browser), i will see only 1 user in a single page (In each browser i see only 1 online user) !
There are some issue for this ? Any suggestion is appreciated.
Thanx
You can use a performance counter to get that number.
Here you have the list of performance counters for ASP.NET. Look for the description of "Sessions Active" under "ASP.NET Application Performance Counters".
Then you can use PerformanceCounter class to get the value of that performance counter for you application.
The problem is that this requires privileges:
To read performance counters in Windows Vista, Windows XP Professional x64 Edition, or Windows Server 2003, you must either be a member of the Performance Monitor Users group or have administrative privileges.
One way to do this would be to impersonate a part of your application to be run by a user with those privileges. It could be an .asmx web service, or the web forms itself which will show the required info. You can impersonate only that service using location and identity impersonate in web.config. Set up a user with the needed privileges and impersonate that user.
Is the server configured to use multiple worker processes per application pool?
ASP.NET State Management Recommendations: http://msdn.microsoft.com/en-us/library/z1hkazw7.aspx
Application scope: The scope of application state can also be a
disadvantage. Variables stored in application state are global only to
the particular process the application is running in, and each
application process can have different values. Therefore, you cannot
rely on application state to store unique values or update global
counters in Web-garden and Web-farm server configurations.
Configuring Web Gardens with IIS 6.0: https://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/659f2e2c-a58b-4770-833b-df96cabe569e.mspx?mfr=true
Related
I am trying to launch a process from a web page's back-end code/app pool. This process will launch an App that i built myself.
For some reason, the process only works / runs when i start it from VS2013... it never works when i launch it from IIS(7.5) itself.
I am on a Windows 7 machine (both IIS host, and App location), and I've setup my web site to only be accessible via internal network.
Here's the code, followed by the config / attempts to fix the issue:
protected void btn_DoIt_Click(object sender, EventArgs e)
{
string file_text = this.txt_Urls.Text;
if (!String.IsNullOrWhiteSpace(file_text))
File.WriteAllText(ConfigurationManager.AppSettings["filePath"], file_text);
ProcessStartInfo inf = new ProcessStartInfo();
SecureString ss = GetSecureString("SomePassword");
inf.FileName = #"........\bin\Release\SomeExecutable.exe";
inf.Arguments = ConfigurationManager.AppSettings["filePath"];
inf.UserName = "SomeUserName";
inf.Password = ss;
inf.UseShellExecute = false;
//launch desktop app, but don't close it in case we want to see the results!
try
{
Process.Start(inf);
}
catch(Exception ex)
{
this.txt_Urls.Text = ex.Message;
}
this.txt_Urls.Enabled = false;
this.btn_DoIt.Enabled = false;
this.txt_Urls.Text = "Entries received and process started. Check local machine for status update, or use refresh below.";
}
Here are the things I've tried to resolve the issue:
Made sure the executing assembly was built with AnyCPU instead of
x86
Ensured that the AppPool that runs the app, also runs under the same account (SomeUsername) as the ProcessStartInfo specified.
Ensured that the specific user account has full access to the executable's folder.
Ensured that IIS_USR has full access to the executable's folder.
Restarted both the app pool and IIS itself many times over implementing these fixes
I am now at a loss as to why this simply will not launch the app... when i first looked into the event log, i saw that the app would die immediately with code 1000:KERNELBASE.dll, which got me on the AnyCPU config instead of X86 fix... that fixed the event log entries but the app still doesn't start (nothing comes up in task manager), and i get no errors in the event log...
if someone could help me fix this problem i would really appreciate it. This would allow me to perform specific tasks on my main computer from any device on my network (phone, tablet, laptop, etc etc) without having to be in front of my main PC...
UPDATE
The comment to my OP, and ultimate answer from #Bradley Uffner actually nailed the problem on the head: My "app" is actually a desktop application with a UI, and in order to run that application, IIS would need to be able to get access to the desktop and the UI, just like if it were a person sitting down in front of the PC. This of course is not the case since IIS is running only as a service account and it makes sense that it shouldn't be launching UI programs in the background. Also see his answer for one way of getting around this.
Your best bet might be to try writing this as 2 parts. A web site that posts commands to a text file (or database, or some other persistent storage), and a desktop application that periodically polls that file (database, etc) for changes and executes those commands. You could write out the entire command line, including exe path command arguments, and switches.
This is the only way I can really think of to allow a service application like IIS to execute applications that require a desktop context with a logged in user.
You should assign a technical user with enough high priviliges to the running application pool. By default the application pool is running with ApplicationPoolIdentity identy which has a very low priviliges.
I have developed a Silverlight application locally on my laptop.
Everything works fine however when I deploy it to the server the web service runs fine, in that it talks to the data base and gets the desired results. My problem lies with the front-end SL app where it is bringing up this error:
Debugging resource strings are unavailable
at System.ComponentModel.AsyncCompletedEventArgs.RaiseExceptionIfNecessary()
at FrontEnd.WebService.UIDReturnCompletedEventArgs.get_Result()
at FrontEnd.Views.Users.client_UIDReturnCompleted(Object sender, UIDReturnCompletedEventArgs e)
at FrontEnd.WebService.Service1SoapClient.OnUIDReturnCompleted(Object state)
Caused by: [Async_ExceptionOccurred]
Arguments:
Debugging resource strings are unavailable. Often the key and arguments provide sufficient information to diagnose the problem. See http://go.microsoft.com/fwlink/?linkid=106663&Version=4.1.10329.0&File=System.dll&Key=Async_ExceptionOccurred
So I went to the link given and it stated that is was a Async_ExceptionOccurred error.
Is this a timing issue? The UIDReturnis a web method that brings back a user ID from the database, this is initiated on page load of the Silverlight page, I thought perhaps the value was not back in time and therefore this is why it was crashing however this works locally and on the test server so perhaps it is an IIS issue?
Here is where the web service is called-
void OnLoadCompleted(object sender, RoutedEventArgs e)
{
string fullUserName = WebContext.Current.User.DisplayName;
string userName = fullUserName.Substring(fullUserName.IndexOf('\\') + 1);
WebService.Service1SoapClient client = new WebService.Service1SoapClient();
client.UIDReturnCompleted += new EventHandler<UIDReturnCompletedEventArgs>(client_UIDReturnCompleted);
client.UIDReturnAsync(userName);
}
The fullUserName is from the current logged in user, perhaps this value has not been loaded yet and due to this it is breaking the connection.
This seems to be related to this post to which I have previously answered: Consume WCF library in Silverlight 4 application
Some Details
I am working with VisualWebGUI, so this app is like ASP.NET, and it is deployed on IIS 7 (for testing)
For my 'Web Site', Anonymous Authentication is set to a specific user (DomainName\DomainUser). In my web.config, I have impersonation on. This is how I got my app to access the share in the first place.
The Problem
There is a point in the the app where we use the Thread class, something similar to:
Thread myThread = new Thread(new ThreadStart(objInstance.PublicMethod));
myThread.Start();
What I have noticed is that I can write to my logs (text file on the share), everywhere throughout my code, except in the thread that I kicked off. I added some debugging output and what I see for users is:
The thread that's kicked off: NT AUTHORITY\NETWORK SERVICE
Everywhere else in my code: DomainName\DomainUser (described in my IIS setup)
OK, for some reason the thread gets a different user (NETWORK SERVICE). Fine. But, my share (and the actual log file) was given 'Full Control' to the NETWORK SERVICE user (this share resides on a different server than the one that my app is running).
If NETWORK SERVICE has rights to this folder, why do I get access denied? Or is there a way to have the thread I kick off have the same user as the process?
You can also get the new thread to impersonate the user that issued the request. For example, if you are starting your request in the Page.Load event it might look like this.
public partial class MyPage : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Thread myThread = new Thread(new ParameterizedThreadStart(ThreadMethod));
myThread.Start(HttpContext.Current.User);
}
private void ThreadMethod(object state)
{
WindowsPrincipal principal = state as WindowsPrincipal;
WindowsImpersonationContext impersonationContext = null;
try
{
if (principal != null)
{
Thread.CurrentPrincipal = principal;
impersonationContext = WindowsIdentity.Impersonate(((WindowsIdentity)principal.Identity).Token);
}
// Do your user specific stuff here...
}
finally
{
if (impersonationContext != null)
{
impersonationContext.Undo();
}
}
}
}
You will notice I passed the Principal from the ASP.NET thread through to the new thread, I obviously assume that you are using Windows Integrated Authentication so I did not do much in the way of error checking, this is just a quick sample.
Note: For VWG you would get the user from the VWG context and run the impersonation code in the appropriate function, this example is ASP.NET jsut because the environment is the same, just I do not know the VWG objects off the top of my head.
NT AUTHORITY\NETWORK SERVICE is a local computer account. To the remote server it looks like your IIS computer's Active Directory account (COMPUTERNAME$). You need to grant access to the log directory to the AD Computer Account of your IIS box.
HTH
I have a simple application written in C# and .Net 2.0 that displays several PowerPoint 2003 files in a loop. (It is going to be used for a information board in our cafeteria) The application works fine on my development machine but when I deploy it to another machine the events I have registered for SlideShowNextSlide and PresentationClose are never fired. I have tried registering the events with this method.
private void InitPPT()
{
app.SlideShowNextSlide += new Microsoft.Office.Interop.PowerPoint.EApplication_SlideShowNextSlideEventHandler(app_SlideShowNextSlide);
app.PresentationClose += new Microsoft.Office.Interop.PowerPoint.EApplication_PresentationCloseEventHandler(app_PresentationClose);
app.SlideShowEnd += new Microsoft.Office.Interop.PowerPoint.EApplication_SlideShowEndEventHandler(app_PresentationClose);
}
And with this method that I found here:
private void InitPPT()
{
IConnectionPointContainer oConnPointContainer = (IConnectionPointContainer)app;
Guid guid = typeof(Microsoft.Office.Interop.PowerPoint.EApplication).GUID;
oConnPointContainer.FindConnectionPoint(ref guid, out m_oConnectionPoint);
m_oConnectionPoint.Advise(this, out m_Cookie);
}
Do I need to register some dll's on the client machine or am I missing something.
I think this was due to the fact that I was trying to run my application from a local user account but impersonate a domain account so I could access network drives. I have changed my application so it only impersonates the domain account while preforming network operations and not at application startup.
I receive an "Access Deined" COMException when I try to connect to a remote IIS 6 server from my C# application that is running under IIS 5.1.
Any ideas? I am experiencing all the same issues with the original questions.
Update - 4/1/09
I found this solution (http://www.codeproject.com/KB/cs/Start_Stop_IIS_Website.aspx) that consists of a window application connecting to an IIS server to start and stop web sites. I am able to run it on my workstation and connect to the IIS server.
Ugh....why can I run this stand alone application but not my ASP.NET application?
Original
I receive an "Access Denied" COMException when I try to connect to IIS from a remote machine using the DirectoryEntry.Exist method to check to see if the IIS server is valid.
string path = string.Format("IIS://{0}/W3SVC", server);
if(DirectoryEntry.Exist(path))
{
//do something is valid....
}
I am a member of an active directory group that has been added to the Administrators groups to the IIS server I am trying to connect to.
Has anyone experience this issue and know how to resolve it?
UPDATE:
#Kev - It is an ASP.NET application. Also, I can connect without an username and password to the remote server through IIS6 Manager.
#Chris - I am trying to connect to the remote server to display the number of virtual directorys and determine the .NET framework version of each directory. See this SO question.
#dautzenb - My ASP.NET application is running under IIS 5.1 trying to connect to an IIS 6 server. I can see fault audits in the security log for my local ASPNET account on the remote server. When I try to debug the application, I am running under my domain account and still get the Access is denied.
UPDATE 2:
#Kev - I was able to establish to create a DirectoryEntry object using the following overload:
public DirectoryEntry
(
string path,
string username,
string password
)
But, all of the properties contain a " threw an exception of type 'System.Runtime.InteropServices.COMException'" while I debug the app.
Also, the AuthenticationType property is set to Secure.
UPDATE 3:
The following two failure audit entries were in the remote IIS server's security event log every time I tried to establish a connection:
First event:
Event Category: Account Logon
Event ID: 680
Log attempt by: MICROSOFT_AUTHENTICATION_PACKAGE_V1_0
Logon account: ASPNET
Source Workstation:
Error Code: 0xC0000234
Second event:
Event Category: Logon/Logoff
Event ID: 529
Logon Failure:
Reason: Unknown user name or bad password
User Name: ASPNET
Domain: (MyDomain)
Logon Type: 3
Logon Process: NtLmSsp
Authentication Package: NTLM
Workstation Name: (MyWorkstationId)
Caller User Name: -
Caller Domain: -
Caller Logon ID: -
Caller Process ID: -
Transited Services: -
Source Network Address: 10.12.13.35
Source Port: 1708
Impersonation is set to true and the username and password are blank. It is using the ASPNET account on the remote IIS server.
If it is an identity problem, you could try setting your IIS 5.1 application to use Integrated Windows Authentication, and then add the following to you web.config on your IIS5.1 web site under system.web to enable impersonation.
<identity impersonate="true"/>
<authentication mode="Windows" />
Since this is an ASP.NET application, it runs in an Application Pool of IIS. This Application Pool runs using a specific user("Local System", "Network Service" or another user).
Does this user have enough rights to connect to a remote server ?
See MSDN for more info.
This looks like it may be a double-hop issue. If you are impersonating the current user of a website using NTLM, that impersonation is only valid on that server (your IIS 5.1 server in this case). If you try to connect to another server using the web site, you are actually going to have issues as it cannot pass the token to another server that was used during impersonation. The same is true if you are debugging your site through your machine, going to another box. Your local machine is authenticating you, but it cannot impersonate you to another server.
All of the solutions I have used in the past require you to hard code the app pool to use an account that has permissions, set the annony. account to a domain account with permissions on the other machine, or use a windows service running on the IIS 5.1 machine, under a domain account, to connect to the other server.
If you are using Kerberos, this wouldn't apply, but AD uses NTLM by default.
Where exactly are you trying to read too? Is it in under the same path as your application?
When I had this problem, I found that simply authenticating my self on a Windows file share solved the problem. From experience, I think that WMI/ADSI/COM doesn't have great support for not-already-authenticated users. I believe this issue occurs when you're not associated with a Windows domain.
If it is indeed a NTLM doublehop issue you could use the SETSPN utility to create service principal named instances for your target IIS servers.
Then you could go into Active Directory, and then allow the computer object (basically the NETWORK SERVICE or LOCAL SERVICE principals) to delegate its credentials to a correctly registered SPN.
Then you could hop-hop-hop all over the place! But, be warned! People can hurt themselves on sharp pointy things when you enable double-hop!
Good KB articles to read:
http://support.microsoft.com/kb/929650
I believe that DirectoryEntry.Exists silently ignores any credentials supplied and uses the creds of the authenticated user. This seems to match the behaviour you've described. For AD work, we never use it for this reason.
I'm sort of stumped at the moment as to why you can't get this working. There is a temporary work around you could try. When instantiating the DirectoryEntry object you could use one of the following constructor overloads:
public DirectoryEntry(
string path,
string username,
string password
)
Documented at: MSDN: DirectoryEntry Constructor (String, String, String)
...or...
public DirectoryEntry(
string path,
string username,
string password,
AuthenticationTypes authenticationType
)
Documented at: MSDN: DirectoryEntry Constructor (String, String, String, AuthenticationTypes)
As it happens I'm building a test AD environment on my virtual server box for a new project to do similar stuff. When I get it up and running I'll have a play around to see if I can reproduce the problem you're encountering. In the meantime let us know what happens if you try these constructor overloads referenced above.
Update (In answer to Michaels comment):
For reasons that evade me just now, we couldn't use DirectoryEntry.Exists() in a particular scenario, there is this snippet of code that gets called now and again in one of our apps:
public static bool MetabasePathExists(string metabasePath)
{
try
{
using(DirectoryEntry site = new DirectoryEntry(metabasePath))
{
if(site.Name != String.Empty)
{
return true;
}
return false;
}
}
catch(COMException ex)
{
if(ex.Message.StartsWith("The system cannot find the path specified"))
{
return false;
}
LogError(ex, String.Format("metabasePath={0}", metabasePath));
throw;
}
catch(Exception ex)
{
LogError(ex, String.Format("metabasePath={0}", metabasePath));
throw;
}
}
You could replace the constructor with one of the ones from above. Admittedly it's a stab in the dark :).