I need to change the app name based on what configuration I'm using in Visual Studio. For example, if I'm in Debug configuration, I want the app name to show as 'App_Debug' in the Application field in the Elmah_Error table. Does anyone have any experience with this? Or is there another way to do it?
This can now be done purely in markup. Just add an applicationName attribute to the errorLog element in the <elmah> section of the web.config file. Example:
<errorLog type="Elmah.SqlErrorLog, Elmah"
connectionStringName="connectionString" applicationName="myApp" />
I've tested this and it works both when logging an exception and when viewing the log via Elmah.axd.
In the case of the OP, one would imagine it can be set programatically too but I didn't test that. For me and I imagine for most scenarios the markup approach is sufficient.
By default, Elmah uses the AppPool's application GUID as the default application name. It uses this as the key to identify the errors in the Elmah_Error table when you look at the web interface that's created through it's HTTP Module.
I was tasked to explore this option for my company earlier this year. I couldn't find a way to manipulate this by default since Elmah pulls the application name from HttpRuntime.AppDomainAppId in the ErrorLog.cs file. You could manipulate it by whatever key you want; however, that is the AppPool's GUID.
With that said, I was able to manipulate the ErrorLog.cs file to turn Elmah into a callable framework instead of a handler based one and allow for me set the ApplicationName. What I ended up doing was modifying ErrorLog.cs to include a property that allowed me to set the name as below:
public virtual string ApplicationName
{
get
{
if (_applicationName == null) { _applicationName = HttpRuntime.AppDomainAppId; }
return _applicationName;
}
set { _applicationName = value; }
}
What you will probably need to do is adjust this differently and set the ApplicationName not to HttpRuntime.AppDomainAppId but, instead, a value pulled from the web.config. All in all, it's possible. The way I did it enhanced the ErrorLog.Log(ex) method so I could use Elmah has a callable framework beyond web applications. Looking back I wish I did the app/web.config approach instead.
One thing to keep in mind when changing the application name in Elmah. The http handler that generates the /elmah/default.aspx interface will no longer work. I'm still trying to find time to circle back around to such; however, you may need to look into creating a custom interface when implementing.
Related
I want to assign Active Directory group name dynamically as an attribute to authorize filter.
Currently we have 2 Active Directory groups, one is for DEV and other is for Prod. However if I have access to dev while debugging in local, I need to have access to the action method. If the AD group is prod, I should not have have access to the action method.
I tried using constants in static class classA
public const string DevActiveDirectoryName = "DevdirectoryName";
public const string ProdActiveDirectoryName = "ProddirectoryName";
My action method is like this:
[Authorize(Roles = ClassA.DevActiveDirectoryName)]
public async task<Iactionresult>GetMemberID()
{
}
The only problem with above solution is if I want to deploy to prod, I need to change code and deploy it. Instead if I can pass value dynamically to attribute that would solve my problem. I have tried many ways. Please suggest the best solution for this case. Is there any workaround for this kind of problem? I appreciate your help.
In order to be able to change the group name for different environments, you need to use configuration settings instead of constants. There are many options on how to provide configuration settings to an ASP.NET Core application. This link gives an overview.
If your application uses the default host builder, it will read configuration settings from a variety of sources, e.g. appsettings.json. You can add a setting to this file (if it does not exist yet, add it to the project), e.g.:
{
"ADGroupName": "ProddirectoryName"
}
For your dev-environment there is a dedicated file appsettings.dev.json that you can use to hold your dev settings:
{
"ADGroupName": "DevdirectoryName"
}
When protecting the controller with an Authorize attribute, you need to provide a constant value to the constructor. As the configuration setting can be changed later, it is (obviously) not constant.
Therefore, you have to set up a policy with a constant name in the ConfigureServices method in Startup.cs:
var adGroupName = Configuration.GetValue<string>("ADGroupName");
services.AddAuthorization(options =>
{
options.AddPolicy("ADGroupPolicy", policy =>
{
// This requirement checks for the group
policy.RequireRole(adGroupName);
});
});
For the controller, you need to add the policy name to the Authorize attribute:
[Authorize("ADGroupPolicy")]
public async task<Iactionresult>GetMemberID()
{
}
You can add an entry in your <appSettings> of your web.Config file and use ConfigurationManager to look up the value that should be assigned to a variable ActiveDirectoryName.
<appSettings>
<add key="ActiveDirectoryName" value="DevdirectoryName" />
... // other keys
</appSettings>
and in your code, you could look up what you have in your web.Config file (Dev for development and Prod for production servers (you dont need to deploy new web.config when deploying new code unless you make changes to it.
public const string ActiveDirectoryName = ConfigurationManager.AppSettings["ActiveDirectoryName"];
If you are using Visual Studio, web.config have two different configs (web.debug.config / web.release.config). You can use debug for development and Release that works on production.
This will stay constant and only your config files are changed,
[Authorize(Roles = ClassA.ActiveDirectoryName)]
public async task<Iactionresult>GetMemberID()
{
}
I want to show some XHTML documents that reference some resources (style sheets, scripts, images, etc). These resources are local, but they do not exist on the file system - instead, they are generated by my application.
Using Android.Webkit.WebView and Android.Webkit.WebViewClient, I can intercept requests and provide these resources flawlessly, using something like this:
internal class MyWebViewClient : WebViewClient
{
public override WebResourceResponse ShouldInterceptRequest (WebView view, string url)
{
/* logic to create a resource stream for the requested url */
return new WebResourceResponse (mimeType, encoding, generatedStream);
}
}
Can I achieve something similar using Xamarin.Forms.WebView and its related classes? If so, how? I haven't noticed in the API documentation any methods that look like they provide equivalent behavior.
The Xamarin.Forms WebView control is very basic at present. The class members show that you wouldn't be able achieve what you are wanting to do.
You can load a HTML resource etc here that is quite useful in determining how to reference local files, if you do decide and go down that route.
Do note, however, that in Xamarin.Forms v1.2.2.6243 on Android the Source property is incorrectly set for URLs. For instance, if you navigate to www.yahoo.com and do a few clicks on that site, you will see some query string parameters etc. However, on Android this always comes back as Source property being www.yahoo.com. Xamarin have created a temporary fix for this, however you have to include and implement your own custom renderer at present to overcome this.
I'm want to be able to set the caller ID on my
XrmServiceContext : Microsoft.Xrm.Client.CrmOrganizationServiceContext
Context that has been generated for crm using svcutil.exe.
As far as I can tell I cant do this on an existing connection and I need to first create an instance of OrganizationServiceProxy set the CallerID and then pass it as a paramater to a new XrmServiceContext which I can then use instead.
However I'm kind of stuck on how I go from a CrmOrganizationServiceContext to having a OrganizationServiceProxy
The program is a separate .Net4.5 application
Any helpful tips or links?
Edit: Found this page just after posting this: http://msdn.microsoft.com/en-us/library/gg695810.aspx
So it may be as simple as:
var connection = new CrmConnection("Xrm");
connection.CallerId = uide;
_serviceContext = new XrmServiceContext(connection);
Edit 2: It was not as simple as that.
Doing this resulted in no change of what data I received.
CrmConnection connection = new CrmConnection("Xrm");
connection.CallerId = Guid.NewGuid();//u.Id;
_serviceContext = new XrmServiceContext(connection);
It compiles and dosen't crash but I was suspicious when I used the id of a user with very low privledges but still got all data back, I then tried generating a new Guid for every instance of the XrmServiceContext but I am still getting everything back. So I am guessing it is not being used.. or I am missing something else.
Edit 3
Doing a WhoAmIRequest after the CallerID has been set still returns the same user that is set in the connection string.
Edit 4
Seems my problems are Cache related.
In my implementation I need to first make a call to the service context to figure out the Guid of the user I want to impersonate. This call is made without CallerID set. If I skip this initial query and just set a specific Guid from the beginning the CallerID works. I'm guessing this is because the service context has cached my original CallerId or something similar.
Now I just have to figure out how to clear the cache in CRM 2013 SDK.
Edit 5
By turning of the cache completly using this guide: http://msdn.microsoft.com/en-us/library/gg695805.aspx I have gotten it to work. I would however prefer if I could just clear it out at the one point I need to instead of disabling it completly.
If someone can show me how to empty the service context cache using code I will mark that as the correct solution
There is a method that can be used when dealing with your "_serviceContext"
You should be able to use: _serviceContext.ClearChanges(); This clears all tracking of a particular entity within the Cache. See the Public Methods Section
The problem is related to the default instanceMode that is defined in the web.config under the microsoft.xrm.client section.
By default, the setting is set to PerRequest
PerRequest – returns the same first instance in the context of a Web
request, for example. one instance for each HttpContext instance.
So, in this case, when you do the initial call to work out which user you want to set the CallerId to, the instance is being 'cached' (for lack of a better word) and on subsequest calls within the same request, this instance is being returned, even if you are creating a new XrmServiceContext
The solution is to change the instanceMode to PerInstance
PerInstance – returns a new instance on each call.
Modify your web.config so that the instanceMode attribute is specified correctly
<microsoft.xrm.client>
<contexts>
<add name="Xrm" type="Xrm.XrmServiceContext, Xrm" serviceName="Xrm" />
</contexts>
<services>
<add name="Xrm" type="Microsoft.Xrm.Client.Services.OrganizationService, Microsoft.Xrm.Client" instanceMode="PerInstance" />
</services>
</microsoft.xrm.client>
Found this information in the article posted by JensB in his 5th edit: http://msdn.microsoft.com/en-us/library/gg695805.aspx
I have a logging class that, well, logs things. I would like to add the ability to automatically have the current page be logged with the messages.
Is there a way to get the information I'm looking for?
Thanks,
From your class you can use the HttpContext.Current property (in System.Web.dll). From there, you can create a chain of properties:
Request
Url and RawUrl
The underlying object is a Page object, so if you cast it to that, then use any object you would normally use from within a Page object, such as the Request property.
It's brittle and hard to test but you can use System.Web.HttpContext.Current which will give you a Request property which in turn has the RawUrl property.
public static class MyClass
{
public static string GetURL()
{
HttpRequest request = HttpContext.Current.Request;
string url = request.Url.ToString();
return url;
}
}
I tried to break it down a little :)
In the past I've also rolled my own logging classes and used Console.Writeln() but really there are a number of good logging options that already exist so why go there? I use NLog pretty much everywhere; it is extremely flexible with various log output destinations including console and file, lots of log format options, and is trivial to set up with versions targeting the various .net frameworks including compact. Running the installer will add NLog config file options to the Visual Studio Add New Item dialog. Using in your code is simple:
// declare in your class
private static Logger logger = LogManager.GetCurrentClassLogger();
...
// use in your code
logger.Debug(() => string.Format("Url: {0}", HttpContext.Current.Request.Url));
I currently have a site where different users can login, and depending on their sub domain, are presented with different data from different databases. I am overriding the SqlMembershipProvider to use a "temp" connection string, that I dynamically set during the Initialize Method, per this post's instructions:
http://forums.asp.net/p/997608/2209437.aspx
public override void Initialize(string name, NameValueCollection config)
{
// intercept the setting of the connection string so that we can set it ourselves...
string specifiedConnectionString = config["connectionStringName"];
ConnectionStringSettings connectionString = ConfigurationManager.ConnectionStrings[specifiedConnectionString];
var fi = typeof(ConfigurationElement).GetField("_bReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);
fi.SetValue(connectionString, false);
connectionString.ConnectionString = WakeflyClientHelper.GetClientConnectionStringByCurrentSubdomain();
config["connectionStringName"] = connectionString.Name;
// Pass doctored config to base classes
base.Initialize(name, config);
}
The problem is that the SqlMembershipProvider class seems "static" in that when multiple users connect from different sub domains, they end up seeing the User Accounts from ONE of the databases, not each of their own. It looks like the Initialize is called by the application, and not on a per request basis.
So my question to you is... What would be the easiest way to implement a solution to this?
I have not written a custom provider before, so I'm not sure how that works, or what the limitations are. And if I write it myself, there is always the possibility of security holes if I overlook something (not to mention the time it will take). Any ideas?
Update 1:
I could have a single database, however, the user's within a given sub domain need the ability to add/edit/delete user's within their own sub domain, without seeing other sub domains' users. Would that be possible under this scheme?
The code for the SQLMembershipProvider is provided here. You could extend/change what you think is necessary by adding the project to your solution and changing the namespace references in web.config.
I have done exactly this using a single membership database to handle all the logins, and then hook them up to the appropriate database depending on the domain in which they logged in.