Today I experienced a weird problem while trying to remotely debug an application built for the .NET 4.0 runtime.
The application resides on a network share and executed by a remote machine. However the application crashes each time during load because of a SecurityException raised by a permission demand in the System.Configuration.ConfigurationManager.GetSection() method. I have not checked if other permission demands in the base class library also cause a security exception but in all cases this shouldn't be happening with the new CLR.
The application is running in full trust (checked it while debugging and as usual this must be always true for intranet applications in CLR 4.0) so I am clueless how a permission demand can cause an exception in this case. When built against the 3.5 SP1 runtime (which first introduced full trust for network shared apps by default) everythings runs as expected.
I pasted the sample code below. Any help is greatly appreciated.
using System;
using System.Configuration;
namespace ConsoleApplication1
{
public sealed class AssetsSection : ConfigurationSection
{
private static readonly ConfigurationProperty s_propPath;
private static readonly ConfigurationPropertyCollection s_properties;
static AssetsSection()
{
s_propPath = new ConfigurationProperty("path", typeof(String));
s_properties = new ConfigurationPropertyCollection()
{
s_propPath
};
}
public static AssetsSection Get()
{
return (AssetsSection) ConfigurationManager.GetSection("test/assets");
}
protected override ConfigurationPropertyCollection Properties
{
get
{
return s_properties;
}
}
public String Path
{
get
{
return (String) base[s_propPath];
}
set
{
base[s_propPath] = value;
}
}
}
class Program
{
static void Main(String[] args)
{
Console.WriteLine(AssetsSection.Get().Path);
Console.ReadLine();
}
}
}
And the App.config file;
<?xml version="1.0"?>
<configuration>
<configSections>
<sectionGroup name="test">
<section name="assets" type="ConsoleApplication1.AssetsSection, ConsoleApplication1"/>
</sectionGroup>
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0,Profile=Client"/>
</startup>
<test>
<assets path="..\Assets"/>
</test>
</configuration>
Try loading the configuration first and open your section on that:
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
AssetsSection configSection = (AssetsSection)config.GetSection("test/assets");
I ran into the same issue with .NET 4 and this works for me.
This is due to a known bug in .NET 4.0 when running the application from a network share.
The follow code fails with a SecurityException. Note that it only fails when you have defined a custom type for the section like in this example AssetsSection:
ConfigurationManager.GetSection("test/assets");
One fix is the solution suggestion by Timo to use a different API. Another solution is to apply the patch provided by Microsoft.
The bug and the related hotfix is filed under KB2580188.
If you add your own class to map the section like this:
[XmlRoot("Interface")]
public class MySectionClass
{
[XmlAttribute()]
public string MyAttr1
{
get;
set;
}
public string MyAttr2
{
get;
set;
}
}
You can use this code:
ConfigurationSection configSection =
ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None).
GetSection("MySection");
XmlSerializer xs = new XmlSerializer(typeof(MySectionClass));
XmlDocument xdoc = new XmlDocument();
xdoc.LoadXml(configSection.SectionInformation.GetRawXml());
XmlNodeReader xnr = new XmlNodeReader(xdoc.DocumentElement);
MySectionClass section = (MySectionClass)xs.Deserialize(xnr);
I'm speculating here, but I suspect it's your configuration file that's not trusted.
In your case, your configuration file is referencing a type ConsoleApplication1.AssetsSection that does not have a strong name that could be used as evidence.
Can you provide more details and the exact error message.
Related
I have the following method in my apiController:
public IEnumerable<something> GetData(DataProvider dataProvider)
{
return dataProvider.GetData();
}
What I need is to invoke this method from javascript and pass it a parameter of DataProvider derived type. I can handle this by passing string, e.g. "FirstProvider" and than write N number of if's in GetData() method to create an instance of proper type.
But is there some way that I can write in web.config file something like:
<DataProviders>
<type = FirstDataProvider, alias = "FirstProvider">
<type = SecondDataProvider, alias = "SecondProvider">
</DataProviders>
Change getData method to:
public IEnumerable<something> GetData(string dataProviderAlias)
{
// get provider type by it's alias from web congfig,
// then instantiated and call:
return dataProvider.GetData();
}
And then find and instantiate the type by it's alias?
Note: I accepted the answer below cause it's pointed me in a right direction, but msdn says that IConfigurationSectionHandler is deprecated.
So I used ConfigurationSection, ConfigurationElementCollection, ConfigurationElement classes instead to build custom config section.
You can store arbitrary data in web.config in the appSettings element:
<configuration>
<appSettings>
<add key="FirstAlias" value="FirstProvider" />
<add key="SecondAlias" value="SecondProvider" />
</appSettings>
</configuration>
And you can then read the values using:
String firstAlias = System.Configuration.ConfigurationManager.AppSettings["FirstAlias"];
String secondAlias = System.Configuration.ConfigurationManager.AppSettings["SecondAlias"];
It's built-in. It's supported. It's where you're supposed to store custom data.
First of all, you can only store valid xml in web.config. <type = FirstDataProvider, alias = "FirstProvider"> is not valid xml.
Second, there are a lot of moving pieces. Please follow the steps carefully -
web.config
Make sure you enter the proper namespace for DataProviders. type="YOUR_APPLICATION.DataProviders".
<configuration>
<configSections>
<section name="DataProviders" type="WebApplication2010.DataProviders"
requirePermission="false"/>
</configSections>
<DataProviders>
<Provider type="FirstDataProvider" alias="FirstProvider"/>
<Provider type="SecondDataProvider" alias="SecondProvider"/>
</DataProviders>
....
</configuration>
Code
public class DataProviders : IConfigurationSectionHandler
{
private static bool _initialized;
public static List<Provider> _providers;
public object Create(object parent, object configContext, XmlNode section)
{
XmlNodeList providers = section.SelectNodes("Provider");
_providers = new List<Provider>();
foreach (XmlNode provider in providers)
{
_providers.Add(new Provider
{
Type = provider.Attributes["type"].Value,
Alias = provider.Attributes["alias"].Value,
});
}
return null;
}
public static void Init()
{
if (!_initialized)
{
ConfigurationManager.GetSection("DataProviders");
_initialized = true;
}
}
public static IEnumerable<Provider> GetData(string dataProviderAlias)
{
return _providers.Where(p => p.Alias == dataProviderAlias);
}
}
public class Provider
{
public string Type { get; set; }
public string Alias { get; set; }
}
Global.asax
For good design practice, you want to read data from web.config only once, and store them in static variables. Therefore, you want to initialize inside Application_BeginRequest of Global.asax.
public class Global : System.Web.HttpApplication
{
void Application_BeginRequest(object sender, EventArgs e)
{
DataProviders.Init();
}
}
Usage
var providers = DataProviders.GetData("FirstProvider").ToList();
Well, I'm not sure if I understand what you want to achieve, but to implement your idea you need a custom section handler.
http://msdn.microsoft.com/en-us/library/2tw134k3(v=vs.100).aspx
In case that you want to create a database connection for specific dataprovider, see this similar question:
ASP.NET: How to create a connection from a web.config ConnectionString?
In my case, I needed to store two byte[] variables in my Web.Config file. Since it must be valid XML data, I simply stored the contents of the arrays like so:
<appSettings>
<add key="Array1" value="0,1,2,3,4,5,6,7,8,9" />
<add key="Array2" value="0,1,2,3,4,5,6,7,8,9" />
</appSettings>
I then call a function that reads this into a C# string, split it into a string[], and parse each string element as a byte into a resulting byte[] and return it.
I am trying to create custom section in app.config file
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="BlogSettings" type="ConsoleApplication1.BlogSettings,
ConsoleApplication1" />
</configSections>
<BlogSettings
Price="10"
title="BLACKswastik" />
</configuration>
C# code :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string title = BlogSettings.Settings.Title;
Console.WriteLine(title);
Console.ReadKey();
}
}
public class BlogSettings : ConfigurationSection
{
private static BlogSettings settings
= ConfigurationManager.GetSection("BlogSettings") as BlogSettings;
public static BlogSettings Settings
{
get
{
return settings;
}
}
[ConfigurationProperty("Price"
, DefaultValue = 20
, IsRequired = false)]
[IntegerValidator(MinValue = 1
, MaxValue = 100)]
public int Price
{
get { return (int)this["Price"]; }
set { this["Price"] = value; }
}
[ConfigurationProperty("title"
, IsRequired = true)]
[StringValidator(InvalidCharacters = " ~!##$%^&*()[]{}/;’\"|\\"
, MinLength = 1
, MaxLength = 256)]
public string Title
{
get { return (string)this["title"]; }
set { this["title"] = value; }
}
}
}
but when I run this code I am getting this error:
The type initializer for 'ConsoleApplication1.BlogSettings' threw an
exception.
Please suggest me whats wrong I am doing.
You should check out Jon Rista's three-part series on .NET 2.0 configuration up on CodeProject.
Unraveling the mysteries of .NET 2.0 configuration
Decoding the mysteries of .NET 2.0 configuration
Cracking the mysteries of .NET 2.0 configuration
Highly recommended, well written and extremely helpful! This will give you a thorough understanding of the .NET configuration system.
Phil Haack also has a great blog post Three easy steps to a custom configuration section that will give you a quick head-start into building your own custom config sections.
To design your own custom section, there's also a handy tool (Visual Studio add-in) called Configuration Section Designer that will make it very easy and simple to create your own custom section and have it build up all the necessary code to handle that custom section.
move this out of the config section
<BlogSettings
Price="10"
title="BLACKswastik" />
You made a new config reference so it can be its own node now.
I am making an attempt to establish a connection to a MySQL server using BLToolkit, and have installed MySql.Data (6.5.4), BLToolkit (4.1.12) and BLToolkit.MySql (4.1.12) via NuGet. I can make a connection to a MSSQL server in a single line, but have had trouble with MySQL and ended up with the following configuration file ...
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<BLToolkit>
<dataProviders>
<add type="BLToolkit.Data.DataProvider.MySqlDataProvider" />
</dataProviders>
</BLToolkit>
<configSections>
<section name="BLToolkit" type="BLToolkit.Configuration.BLToolkitSection, BLToolkit.4" />
</configSections>
<connectionStrings>
<add name="Test"
connectionString="Data Source=localhost;Port=3306;Database=bltest;User ID=root;Password=root;"
providerName="MySql.Data.MySqlClient" />
</connectionStrings>
</configuration>
I have extended the DbManager class to implement a reference to the tables, and passed the name of the connection string into the base class. This is how I implemented this behaviour, which should be telling BLToolkit to load the connectionString from the configuration file ...
class BlDb : DbManager {
public BlDb()
: base("Test") {
return;
}
public Table<Car> Car { get { return GetTable<Car>(); } }
public Table<Make> Make { get { return GetTable<Make>(); } }
}
An exception, however, is thrown. The exception is "The type initializer for 'BLToolkit.Data.DbManager' threw an exception." with the inner exception being "Configuration system failed to initialize". How should I proceed? Please note that a similar question does exist on SO, Getting BLToolkit to work with MySQL, which might be a helpful reference for you but doesn't make any sense whatsoever to me. Is installing both NuGet packages not enough?
Firts you need to add the reference to the BLToolkit.Data.DataProvider.MySql.4.dll to your project. Then modify your extended DbManager class to look as the following
class BlDb : DbManager
{
public BlDb()
: base( new BLToolkit.Data.DataProvider.MySqlDataProvider(), "Server=myServerAddress;Database=myDataBase;Uid=myUsername;Pwd=myPassword" )
{
}
public Table<Car> Car { get { return GetTable<Car>(); } }
public Table<Make> Make { get { return GetTable<Make>(); } }
}
you can replace the hard-coded connection string and return it from your app.config file like ConfigurationManager.ConnectionStrings["Test"].ConnectionString
First of, let me start by saying I have no experience of doing endpoint/networking type of stuff, so my question might seem a bit stupid, so please bear with me :)
I am working on porting an App written for Windows Phone 7 onto Windows 8 (Metro app). In the original App, there was a ServicesReference.ClientConfig file which defined the URL, bindings and other bits for the App to connect to the server (addresses changed):
<client>
<endpoint address="https://someurl.com/userservice.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_UserServices"
contract="UserApi.UserServices" name="User_Services" />
<endpoint address="https://someurel.com/dataservice.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_DataServices"
contract="DataApi.DataServices" name="Data_Services" />
Also, in the WP7 project, there were already two "Service References" added (one for User Services and one for Data Services), with supporting Reference.cs generated files. When I tried adding the service references into the Win8 project (VS2012), it generated a blank reference.cs file, so I simply added the Reference.cs file from the WP7 project into the W8 project, and also copied the ServiceReferences.ClientConfig file into the W8 project (so in terms of directory structure, it looked identical to the WP7 project).
I think these Reference.cs files are the ones which provide the interface for the contracts
Now, when I run my W8 app, I get an error during the part where it needs access to the service:
InvalidOperationException was unhandled by user code
Could not find endpoint element with name
'User_Services' and contract
'UserApi.UserServices' in the ServiceModel client
configuration section. This might be because no configuration file was
found for your application, or because no endpoint element matching
this name could be found in the client element.
So I figured the App isn't using the ServicesReferces.ClientConfig file to pickup the endpoints and network adresses, or it wasn't finding the Reference.cs files which I have importes into the project. So, assuming first it is not finding the endpoints correctly through the ServicesReferences.ClientConfig file, is it possible to do the same in code?
All I got so far is this:
BasicHttpBinding binding = new BasicHttpBinding();
EndpointAddress endpoint = new EndpointAddress(new Uri("https://someurl.com/someservice.svc"));
but I don't how to take this further (I added this into App.xaml.cs)
Hope the question makes sense. If there is any further information you need, please let me know and I will try to find out about it while I go and educate myself more on this endpoint business
Thanks in advance
I had the same problem and I tried to wrap everything in some classes.. This is what I did:
First of all, I created a class called ClientService where it creates and wraps the EndpointAdress:
EDIT for Win8:
public class ClientService
{
public Type ContractType {get;set;}
public EndpointAdress EndpointAdress {get;set;}
public Binding Binding { get; private set; }
public ClientService(Type contractType)
{
ContractType = contractType;
CreateEndpoint();
CreateBinding();
}
private void CreateEndpoint()
{
EndpointAdress = new EndpointAddress(....) //You can get some parameters about the service adress in the Constructor of this class
}
private void CreateBinding()
{
Binding = new BasicHttpBinding(); //Or your specific Binding
}
}
Once I have this, I create a static class with all my client registrations. I add all of them once I start my app. Something like this:
ClientServices.AddClientService(new ClientService(typeof(IYourService));
public static class ClientServices
{
private static readonly Dictionary<Type, ClientService> _clientServices;
static ClientServices()
{
_clientServices = new Dictionary<Type, ClientService>();
}
public static void AddClientService(ClientService clientService)
{
if (!_clientServices.ContainsKey(clientService.ContractType))
{
_clientServices.Add(clientService.ContractType, clientService);
}
}
public static ClientService GetClientServiceBy(Type contract)
{
if (_clientServices.ContainsKey(contract))
{
return _clientServices[contract];
}
throw new ArgumentException(string.Format("The contract's Type {0} is not registered. Please register the client's endpoint.", contract));
}
}
So, when my application starts I have all my client endpoints registered in a static class. Now when I want to call a service I have a wrapper called ServiceInvoker. I use it like this whenever I want to call a Service:
var invoker = new ServiceInvoker();
var result = invoker.InvokeService<IMyService, MyObjectReturnType>(
proxy => proxy.DoSomething(myParameters));
return result;
Where InvokeService looks like this:
public TResult InvokeService<TServiceContract, TResult>(Func<TServiceContract, TResult> invokeHandler) where TServiceContract : class
{
ICommunicationObject communicationObject;
var arg = CreateCommunicationObject<TServiceContract>(out communicationObject);
var result = default(TResult);
try
{
result = invokeHandler(arg);
}
catch (Exception ex)
{
throw;
}
finally
{
try
{
if (communicationObject.State != CommunicationState.Faulted)
communicationObject.Close();
}
catch
{
communicationObject.Abort();
}
}
return result;
}
private TServiceContract CreateCommunicationObject<TServiceContract>(out ICommunicationObject communicationObject)
where TServiceContract : class
{
var clientService = GetClientService(typeof(TServiceContract));
var arg = new ChannelFactory<TServiceContract>(clientService.Binding, clientService.EndpointAdress).CreateChannel();
communicationObject = (ICommunicationObject)arg;
return arg;
}
private ClientService GetClientService(Type type)
{
var clientService = ClientServices.GetClientServiceBy(type);
return clientService;
}
The main problem here is that since DLL's cannot be referenced in a Windows Store App, the only way to make this example work is to copy all Service Interfaces and possible ojects that we transfer to a Class Library (Windows Store apps). This way we will be able to create a channel and connect to the WCF service.
Copying the interfaces can be a workaround but is NOT a good approach.
Service Reference or other code generation tools are the way to go.
In addition, async and await are not possible in this scenario.
**ServiceInvoker apprach is used from creating WCF ChannelFactory
Well, I'm making my foray into this fantastic site with a question about the correct way to inject configuration settings into application components. So, the overview is : I have an application written in C# .Net 3.5. It consists of 3 assemblies - a Core, a Data and a Service. The data & service assemblies require settings retrieved from the app.config, which is done via a settings file, eg.
Code :
public static String RequestQueueConnectionString
{
get { return ConnectionSettings.Default.RequestQueueConnectionString; }
}
Config :
<applicationSettings>
<MyNamespace.Data.ConnectionSettings>
<setting name="RequestQueueConnectionString" serializeAs="String">
...
Now, the assemblies are all setup using StructureMap for IoC - which to my mind should provide the answer to what I am looking for, but I just can't quite see it!
IoC :
public static void ConfigureStructureMap(IContainer container)
{
container.Configure(x => ...
...
What I want to be able to do is to inject a configuration class already populated into the IoC container such that those settings are used for that assembly, NOT those specified in the settings file / app.config. So perhaps :
public static void ConfigureStructureMap(IContainer container, MyConfigClass config)
{
container.Configure(x => x.For<DataConfig>()
.Singleton()
.Use ???
...
I hope I have provided enough details here - forgive a newbie if I have not and please let me know what else would be helpful in answering this!
So, after a lot of searching and trial and error, I was presented with #default.kramer's link, which I duely followed! With a little bit of trial and error, again (best way in my opinion), I managed to get the solution I was looking for. Now, whilst you can follow the link (and I would highly suggest doing so), I am going to post the solution to my question as I implemented it. Hopefully this might help someone with a similar problem.
So, I now have my configuration setup class like so :
public static class DispatchConfiguration
{
public static void ConfigureStructureMap(IContainer container, IDispatchConfiguration dispatchConfig)
{
DispatchProcessBatchSize = dispatchConfig.DispatchProcessBatchSize;
ServiceIsActive = dispatchConfig.ServiceIsActive;
...
}
Now, before I was using a settings file to retrieve the configuration out of the app.config file. This was obviously good for ensuring I had flexibility in changing my config settings, but it left me with the problem of not being able to easily test those settings. Say 9/10 tests required the service to be active, but 1 test wanted to test "ServiceIsActive = false;", now I'm in trouble.
Now, however, I am able to inject the configuration from the test :
[Given(#"Config\.IsServiceActive returns false")]
public void GivenConfig_IsServiceActiveReturnsFalse()
{
var settings = new DispatchSettings
{
ServiceIsActive = false,
DispatchProcessBatchSize = 100,
UpdatedBy = "Unit Test"
};
DispatchConfiguration.ConfigureStructureMap(ObjectFactory.Container, settings);
}
And then in the real world I am able to get the settings from app.config :
public void Start(String[] args)
{
var dispatchConfig = this.GetDispatchConfiguration();
DispatchConfiguration.ConfigureStructureMap(ObjectFactory.Container, dispatchConfig);
...
}
private IDispatchConfiguration GetDispatchConfiguration()
{
var config = (DispatchSettings)ConfigurationManager.GetSection("DispatchSettings");
return config;
}
And then the actual config class looks like :
[XmlRoot(ElementName = "DispatchSettings", Namespace = "")]
public sealed class DispatchSettings : IDispatchConfiguration
{
public Int32 DispatchProcessBatchSize { get; set; }
public Boolean ServiceIsActive { get; set; }
...
}
For the sake of completeness the interface looks like so :
public interface IDispatchConfiguration
{
Int32 DispatchProcessBatchSize { get; }
Boolean ServiceIsActive { get; }
...
}
And finally, the config file looks like this :
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="DispatchSettings" type="MyNamespace.XmlConfigurator, MyNamespace.Core" />
</configSections>
<DispatchSettings type="MyNamespace.DispatchSettings, MyNamespace.Core">
<ServiceIsActive>True</ServiceIsActive>
<DispatchProcessBatchSize>100</DispatchProcessBatchSize>
</DispatchSettings>
Now, anyone with a keen eye will spot "MyNamespace.XmlConfigurator". I found this on one of my Google journeys, and the code allows you to deserialize an Xml config into a class of your desire (as shown in this example). So, to ensure you have the complete code to make this technique work, below is the code for the XmlConfigurator. I cannot remember where I came across it, but a big thanks to the person who wrote it!!
public sealed class XmlConfigurator : IConfigurationSectionHandler
{
public XmlConfigurator()
{
}
public object Create(object parent, object configContext, XmlNode section)
{
XPathNavigator navigator = null;
String typeName = null;
Type sectionType = null;
XmlSerializer xs = null;
XmlNodeReader reader = null;
try
{
Object settings = null;
if (section == null)
{
return settings;
}
navigator = section.CreateNavigator();
typeName = (string)navigator.Evaluate("string(#type)");
sectionType = Type.GetType(typeName);
xs = new XmlSerializer(sectionType);
reader = new XmlNodeReader(section);
settings = xs.Deserialize(reader);
return settings;
}
finally
{
xs = null;
}
}
}
And there you have it! I hope this allows anyone with a similiar issue to resolve it and is clear enough to follow!