Application insights: no data for dependency calls - asp.net

ASP.NET site hosted on Azure VM. ApplicationInsights Status Monitor installed on VM. Default ApplicationInsights.config created by "Add AppInsights" menu in Visual Studio, only custom initializer added instead of ikey:
<Add Type="WebSite.WebSiteTelemetryInitializer, WebSite" />
Code:
public class WebSiteTelemetryInitializer : ITelemetryInitializer
{
public void Initialize(ITelemetry telemetry)
{
TelemetryConfiguration.Active.InstrumentationKey = WebConfigurationManager.AppSettings["ikey"];
telemetry.Context.User.Id = Environment.UserName;
telemetry.Context.Session.Id = Guid.NewGuid().ToString();
telemetry.Context.Component.Version = typeof(WebSiteTelemetryInitializer).Assembly.GetName().Version.ToString();
}
}
All works as expected, but there is no performance data (Cpu, memory). After adding apppool user to Performance Monitor Users group:
$group = [ADSI]"WinNT://$Env:ComputerName/Performance Monitor Users,group"
$ntAccount = New-Object System.Security.Principal.NTAccount("IIS APPPOOL\DefaultAppPool")
$strSID = $ntAccount.Translate([System.Security.Principal.SecurityIdentifier])
$user = [ADSI]"WinNT://$strSID"
$group.Add($user.Path)
there is no data for dependency calls.
UPDATE
There are 3 repeating trace logs:
AI (Internal): Complete creating shadow copy of extension,
extensionBaseDirectory: C:\inetpub\wwwroot\site\bin, extensionName:
Microsoft.ApplicationInsights.Extensions.Intercept with error System.UnauthorizedAccessException: Access to the path 'C:\Windows\system32\config\systemprofile' is denied.
AI (Internal): Extension attach failure, unable to attach, baseFolder: C:\inetpub\wwwroot\site\bin, nativeExtensionName: Microsoft.ApplicationInsights.Extensions.Intercept
AI (Internal): [msg=RemoteDependencyModule failed];[msg=System.InvalidOperationException: Failed to attach extension, hresult: 2147500037

Remote dependencies:
Ok, so that is what is preventing ApplicationInsights from collecting dependencies:
AI (Internal): Complete creating shadow copy of extension, extensionBaseDirectory: C:\inetpub\wwwroot\site\bin, extensionName: Microsoft.ApplicationInsights.Extensions.Intercept with error System.UnauthorizedAccessException: Access to the path 'C:\Windows\system32\config\systemprofile' is denied.
C:\Windows\system32\config\systemprofile is what is set as a temp folder for your process. You need to change temp folder for the process and make sure that your application can write there. (ApplicationInsights is coping native binaries there that are used by profiler. Temp folder is also used when you have temporary internet access issues. It saves events that were not sent and sends them when connection is restored.)
Performance counters:
In order to collect performance counters the user that application pool runs under (usually it's ApplicationPoolIdentity) should be a member of Performance Monitor Users group on the box. Ensure that it's added there and you should do iisreset after adding the user to the group otherwise changes will not take effect.
Described here at the bottom:
http://blogs.msdn.com/b/visualstudioalm/archive/2014/12/11/updated-application-insights-status-monitor-to-support-12-and-later-application-insights-sdk.aspx

Just to add, you can change the temp folder that Application Insights writes to by editing the end of applicationsinsights.config file and adding the location of temp folder. Here's what I've done:
<TelemetryChannel Type="Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel.ServerTelemetryChannel, Microsoft.AI.ServerTelemetryChannel">
<StorageFolder>D:\AITempFolder</StorageFolder>
Hope this helps someone else too.

Related

IIS using Microsoft.Web.Administration and commiting changes

goal
Change IIS bindings and swap virtual directories on a per request basis. A simple application will open, replace and commit, using the Microsoft.Web.Administration. Following is a simplified flow:
code
ServerManager = New ServerManager()
config = ServerManager.GetApplicationHostConfiguration()
SiteList = config.GetSection("system.applicationHost/sites")
SitesCollection = SiteList.GetCollection()
_site = SitesCollection.FirstOrDefault(Function(f) f.GetAttributeValue("name").ToString() = "XXX")
_bindings = _site.GetCollection("bindings")
_bind As ConfigurationElement = _bindings.CreateElement("binding")
_bind("protocol") = "http"
_bind("bindingInformation") = String.Format("*:80:{0}", "www.zzz.yyy")
_bindings.Add(_bind)
ServerManager.CommitChanges()
problem
This code run on an administrator authenticated web page, and before the call, the thread is impersonated to make sure the privileges are in place. I'm allowed to read the .config but not to write! I also confirmed that, before any call, the thread is running as Administrator. I also tried using a LocalService pool but again, no luck.
the error
Filename: \\?\C:\Windows\system32\inetsrv\config\applicationHost.config
Error: Cannot write configuration file due to insufficient permissions
hresult: 0x80070005
at Microsoft.Web.Administration.Interop.AppHostWritableAdminManager.CommitChanges()
After some checking and experiment I find out that the way to make it work was
Do not use authentication on the application.
Do not use impersonation.
LocalService does not work.
Run it on a pool with enough privileges (administrator)
Looks like using impersonation breaks it again.
This is NOT the setting I wanted but I think I can survive and move the app to this unsecure pool, work the changes and the move it back to a generic ApplicationPoolIdentity.

The permissions granted to user 'DOMAIN\MY-DESK$' are insufficient for performing this operation. (rsAccessDenied)

My desktop name is DOMAIN\MY-DESK. So the error is regard as to my desktop rather than my Windows credential.
I searched the web most of them are related to DOMAIN\UserName issue. The local report url is http://localhost/WebAdminOrion/Administrative/Reports
The report page is in a asp.net web application. I have the following code in the report page.
ReportParameter[] prm = new ReportParameter[Request.QueryString.Keys.Count - 1];
ReportViewer1.ServerReport.SetParameters(prm);
I get the error at the line of setting parameters.
By this, I think that the solution might be to configure the file. However the file C:\Program Files\Microsoft SQL Server\MSRS12.MSSQLSERVER\Reporting Services\ReportServer\rsreportserver.config has 292 lines. One section is
<Authentication>
<AuthenticationTypes>
<RSWindowsNTLM />
</AuthenticationTypes>
<RSWindowsExtendedProtectionLevel>Off</RSWindowsExtendedProtectionLevel>
<RSWindowsExtendedProtectionScenario>Proxy</RSWindowsExtendedProtectionScenario>
<EnableAuthPersistence>true</EnableAuthPersistence>
Not sure how to configure it.
Resolved it and shamed. The permissions granted to user 'servername/iusr-username' are insufficient for performing this operation. (rsAccessDenied)
You need to go into your SSRS ReportManager and configure the security settings.
Through Properties
-> Security -> New Role Assignment-> Then add the appropriate domain group. For my case, it needs to add by desk name as "DOMAIN\DESK$".

Directory.CreateDirectory failed on Remote Server

I am working on a small project, in asp.net mvc3, that would copy the deployment files from a local drive to a share drive on a window server 2008 R2 server. I am connected using WMI, and the connection is successful. However, I tried to create a folder, and I receive the message "Logon failure: unknown user name or bad password." Here is a sample code:
bool isConnected = false;
options.Username = user.Name.Trim();
options.Password = user.password.Trim();
mScope = new ManagementScope("\\\\xxx.xxx.xxx.xxx\\root\\cimv2", options);
mScope.Connect();
if (mScope.IsConnected == true)
{
//I've gotten to this point. Then, the code below throw the exception
Directory.CreateDirectory(#"\\\\xxx.xxx.xxx.xxx\Tester\shareFile.txt");
isConnected = true;
}
I'd like to know what am I doing? Is that the right way of doing it?
it is the correct way however it will be the current user you are trying to access that gets passed to the remote computer to create the directory. The management scope at this point has nothing to do with Directory.CreateDirectory. These are 2 different "worlds". you do give the creds to ManagementScope but this has no affect on Directory.CreateDirectory. you could use impersonation to do what you are wanting to:
How do you do Impersonation in .NET?
it is unclear though if you are doing this in ASP.NET/MVC or a different platform. your tags indicate ASP.NET MVC but not your main question.
remember, if you are using ASP.NET/MVC, the credentials of the app pool are being used to perform such actions.

ServiceController.start() and ServiceController.stop() are throwing exceptions?

The following code is throwing Exception. I don't get what mistake I am making in the code. Can somebody help me figure out please. I think it is of some security rights issue. If so, how can I give the security rights to any user or application to access this windows service programmatically?
Dim sc As New ServiceController
sc.ServiceName = "DataLoad"
If sc.Status = ServiceControllerStatus.Stopped Then
sc.Start()
Else
sc.Stop()
End If
Exception:
System.InvalidOperationException: Cannot open DataLoad service on computer '.'. --->
System.ComponentModel.Win32Exception: Access is denied --- End of inner exception stack trace --- at
System.ServiceProcess.ServiceController.GetServiceHandle(Int32 desiredAccess) at
System.ServiceProcess.ServiceController.Start(String[] args) at
System.ServiceProcess.ServiceController.Start() at
WEBSITE.DataLoad.Submit1_ServerClick(Object sender, EventArgs e) in C:\Inetpub\wwwroot\WEBSITE\a\DataLoad.aspx.vb:line 46
Thank you!
You can use the subinacl tool for that
SUBINACL /SERVICE \\MachineName\ServiceName /GRANT=[DomainName\]UserName[=Access]
To be specfic for your case:
subinacl /service DataLoad /GRANT=YOURDOMAIN\[User in appdomain for WEBSITE]=TO
Where TO means
T : Start Service
O : Stop Service
all options for [Access] are:
F : Full Control
R : Generic Read
W : Generic Write
X : Generic eXecute
L : Read controL
Q : Query Service Configuration
S : Query Service Status
E : Enumerate Dependent Services
C : Service Change Configuration
T : Start Service
O : Stop Service
P : Pause/Continue Service
I : Interrogate Service
U : Service User-Defined Control Commands
See Method 3 in this kb article
I found a solution to this problem by providing the machine name of the machine which is currently executing the service in the ServiceController overloaded constructor that takes 2(two) arguments i.e.
public ServiceController(/my service's name string/, System.Environment.MachineName/this machine which is executing the service/)
The version of .Net this solution was tested on was 4.5, hope this helps anyone still looking for a solution.
Here is what you need to do in code:
ServiceController serviceController = new ServiceController("myServiceName", System.Environment.MachineName);
GetServiceHandle requires some access rights. If it works when you run it as an Admin user, but not as a normal user, then maybe this article can help.
It clearly shows you how to manually give a Windows User rights to start and stop services (or set other permissions):
http://thommck.wordpress.com/2011/12/02/how-to-allow-non-admins-to-start-and-stop-system-services/
In my case, I determined that I needed to adjust the security on my service to allow it be be restarted by a separate "watchdog" service if my service fails.
First, open mmc.exe, then add the "Security Configuration and Analysis" and Security Templates" snap-ins.
Then create a new blank security template from the "Security Templates" item, give it a name, and hit OK to save it on your local disk drive somewhere convenient.
Then open "Security Configuration and Analysis" and choose "Open Database...", give it a name, and save it in the same directory as the previous step. When an "Import Template" window appears, open the *.inf file in the same directory.
Next, right-click "Security Configuration and Analysis" and choose "Analyze Computer..." The following will appear:
Double-click on "System Services", locate and double-click on your service, then click the checkbox "Define this policy in the database" and click on the "Edit Security" button.
This is where it becomes different than what is described in the link #JOG posted since I am using Windows 8.1--I enabled "start, stop and pause" for "INTERACTIVE" and "SERVICE"
FYI, I performed the above by following this guide as #JOG suggested: https://thommck.wordpress.com/2011/12/02/how-to-allow-non-admins-to-start-and-stop-system-services/
If you are already having the Service user as LocalSystem(the high privilage user) the problem is not security. Also I had that problem before and its the status vrs starting it again or stopping it when already commande to stop().
You see the service status its not changed on demand, so even if you coded
//this will start the process but the
//sc status will take some time to change
//when that happens and you try to start
//the already started service it will give you
//your error
servicec.start();
Soo you need to do this:
msdn ServiceController.waitforstatus
Dim sc As New ServiceController
sc.ServiceName = "DataLoad"
If sc.Status = ServiceControllerStatus.Stopped Then
sc.Start()
// this makes it wait for the status to change
// and no it wont slow down anything at all.
sc.waitforstatus(ServiceControllerStatus.started)
Else
sc.Stop()
sc.waitforstatus(ServiceControllerStatus.stopped)
End If
This will solve your problem like it did mine.

How do I access database via virtual folder which points at a remote share

I'm having a problem getting access to a database which lives on a remote server.
I have a ASP.NET 2.0 webpage that is trying to connect to a database.
The database is accessed via a virtual folder (which I set up in IIS).
The virtual folder points at a remote share which contains the database.
The virtual folder (in the web apps root directory) is pointing at a share on a remote server via a UNC path:
\\databaseServerName\databaseFolder$\
The virtual folder has 'read' and 'browse' permissions set to 'true'.
I store the connection string in the 'appSettings' section of the web.config:
<add key="conStrVirtual" value="Provider=Microsoft.Jet.OleDb.4.0;Data Source=http://webAppServerName/virtualFolderName/databaseName.MDB;Jet OLEDB:Database Password=dumbPassword;"/>
The connection object is declard on my .aspx page:
Dim objConnVirtual As New OleDbConnection(ConfigurationManager.AppSettings("conStrVirtual"))
Here is the code that tries to use the connection object:
Public Sub Test()
If objConnVirtual.State <> ConnectionState.Open Then
objConnVirtual.Open()
End If
Dim cmd As OleDbCommand = New OleDbCommand("SELECT * FROM TableName", objConnVirtual)
objDR = cmd.ExecuteReader()
If objDR.Read() Then
response.write("Shazaam! Data shows up here")
End If
objDR.Close()
objConnVirtual.Close()
End Sub
When I run the above code I get the following error (on this line of the code 'objConnVirtual.Open()':
Exception Details: System.Data.OleDb.OleDbException: Not a valid file name.
I have checked the database name and it is correct (even copy/pasted it to make sure)
If I put the 'Data Source' section of the connection string into the address bar of my browser I can successfully see the contents of the share on the remote server.
Not sure if this is a problem with permissions or with the code.
I have googled the crap out of this but have not been able to find a solution.
Any help is much appreciated.
When accessing a remote Access MDB database, you have to specify a UNC path like \\remoteMachine\Share\test.mdb.
Make sure your application pool identity has the right permissions to connect to the remote share. By default on IIS 6 you are working with the Network Service account, which is by default not allowed to access a remote share.
The best way is to let the AppPool run with a dedicated service user.
What is the account being used on your server when your web app tries to read the db file? Whatever this user account is, it needs to have permissions to read that folder/file. In IIS6 you can configure the virtual folder to use any user account... on the Directory Security tab there's an Edit button under Authentication and access control.
It seems likely that your error message is just a generic error message, and the permissions problem is your real issue.
make sure the two servers have internal access to each other and also specify the ip & port of db server in your connection string .
Update
I should also mention that it works on my machine (but not once loaded up to the production box) if I declare the connection string in the 'appSettings' section of the web.config like this:
<add key="conStrVirtual" value="Provider=Microsoft.Jet.OleDb.4.0;Data Source=\\databaseServerName\databaseFolder$\databaseName.MDB;Jet OLEDB:Database Password=dumbPassword;"/>
This leads me to think that it could be an issue with needing to use domain credentials other than the local IUSER account.
UPDATE
First up, thank you to everyone who submitted answers.
However, we ended up not using the 'connect to remote database via virtual folder' method because the complexity of the permissions needed to get this to work was causing us more problems than it was worth. We put the UNC path back into the connection string, which may not be the best way to do this, but is working for us.

Resources