From c356bc76a022cae94725d7081fc2a37e14de7d81 Mon Sep 17 00:00:00 2001 From: eeichinger Date: Tue, 19 May 2009 04:09:27 +0000 Subject: [PATCH] made Spring.NET partial trust ready --- .../DataBinding/EmployeeInfo/Default.aspx.cs | 26 +- .../DataBinding/EventHandling/Default.aspx | 2 +- .../DataBinding/EventHandling/Default.aspx.cs | 5 +- .../DataBinding/HelloWorld/Default.aspx.cs | 4 +- .../DataBinding/Lists/Default.aspx.cs | 8 +- .../EmployeeInfoEditor.ascx.cs | 26 +- .../RobustEmployeeInfo/Default.aspx | 2 +- .../RobustEmployeeInfo/Default.aspx.cs | 30 +- .../Navigation/Default.aspx | 2 +- .../src/Spring.WebQuickStart.2005/Web.Config | 19 +- .../web_mediumtrust.config | 74 + src/Spring/Spring.Core/AssemblyInfo.cs | 26 +- .../Core/IO/ResourceHandlerRegistry.cs | 532 +-- .../DataBinding/AbstractSimpleBinding.cs | 6 +- .../Spring.Core/Expressions/IndexerNode.cs | 15 +- .../Dynamic/DynamicReflectionManager.cs | 493 +-- .../Spring.Core/Spring.Core.2008.csproj | 5 +- src/Spring/Spring.Core/Util/ObjectUtils.cs | 3 +- .../Spring.Core/Util/ReflectionUtils.cs | 2896 +++++++++-------- .../Spring.Core/Util/SecurityCritical.cs | 50 + src/Spring/Spring.Core/Util/SystemUtils.cs | 4 +- .../EnterpriseServicesExporter.cs | 2 +- src/Spring/Spring.Web/AssemblyInfo.cs | 19 +- .../Context/Support/WebSupportModule.cs | 20 +- src/Spring/Spring.Web/Spring.Web.2008.csproj | 3 + .../Spring.Web/Util/SecurityCritical.cs | 66 + .../Web/Support/AbstractHandlerFactory.cs | 78 +- .../Spring.Web/Web/Support/ControlAccessor.cs | 185 +- .../Web/Support/ControlCollectionAccessor.cs | 26 +- .../InterceptControlCollectionStrategy.cs | 13 +- .../Web/Support/LocalResourceManager.cs | 30 +- .../Web/Support/PageHandlerFactory.cs | 2 - ...upportsWebDependencyInjectionOwnerProxy.cs | 15 +- .../Spring.Web/Web/UI/Controls/Panel.cs | 7 + src/Spring/Spring.Web/Web/UI/Page.cs | 14 +- src/Spring/Spring.Web/Web/UI/UserControl.cs | 13 + .../Reflection/Dynamic/BasePropertyTests.cs | 15 +- .../Reflection/Dynamic/DynamicFieldTests.cs | 50 +- .../Spring.Core.Tests/SecurityTemplate.cs | 526 +++ .../Spring.Core.Tests.2008.csproj | 1 + .../ReflectionUtilsMemberwiseCopyTests.cs | 71 +- 41 files changed, 3264 insertions(+), 2120 deletions(-) create mode 100644 examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/web_mediumtrust.config create mode 100644 src/Spring/Spring.Core/Util/SecurityCritical.cs create mode 100644 src/Spring/Spring.Web/Util/SecurityCritical.cs create mode 100644 test/Spring/Spring.Core.Tests/SecurityTemplate.cs diff --git a/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/DataBinding/EmployeeInfo/Default.aspx.cs b/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/DataBinding/EmployeeInfo/Default.aspx.cs index d54b3009..c517c8b0 100644 --- a/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/DataBinding/EmployeeInfo/Default.aspx.cs +++ b/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/DataBinding/EmployeeInfo/Default.aspx.cs @@ -21,19 +21,19 @@ public partial class DataBinding_EmployeeInfo_Default : Spring.Web.UI.Page /// protected override void InitializeDataBindings() { - BindingManager.AddBinding("txtId.Text", "Employee.Id"); - BindingManager.AddBinding("txtFirstName.Text", "Employee.FirstName"); - BindingManager.AddBinding("txtLastName.Text", "Employee.LastName"); - BindingManager.AddBinding("txtDOB.Text", "Employee.DateOfBirth"); - BindingManager.AddBinding("txtSalary.Text", "Employee.Salary"); - BindingManager.AddBinding("rbgGender.Value", "Employee.Gender"); - BindingManager.AddBinding("ddlAddressType.SelectedValue", "Employee.MailingAddress.AddressType"); - BindingManager.AddBinding("txtStreet1.Text", "Employee.MailingAddress.Street1"); - BindingManager.AddBinding("txtStreet2.Text", "Employee.MailingAddress.Street2"); - BindingManager.AddBinding("txtCity.Text", "Employee.MailingAddress.City"); - BindingManager.AddBinding("txtState.Text", "Employee.MailingAddress.State"); - BindingManager.AddBinding("txtPostalCode.Text", "Employee.MailingAddress.PostalCode"); - BindingManager.AddBinding("txtCountry.Text", "Employee.MailingAddress.Country"); + BindingManager.AddBinding("FindControl('txtId').Text", "Employee.Id"); + BindingManager.AddBinding("FindControl('txtFirstName').Text", "Employee.FirstName"); + BindingManager.AddBinding("FindControl('txtLastName').Text", "Employee.LastName"); + BindingManager.AddBinding("FindControl('txtDOB').Text", "Employee.DateOfBirth"); + BindingManager.AddBinding("FindControl('txtSalary').Text", "Employee.Salary"); + BindingManager.AddBinding("FindControl('rbgGender').Value", "Employee.Gender"); + BindingManager.AddBinding("FindControl('ddlAddressType').SelectedValue", "Employee.MailingAddress.AddressType"); + BindingManager.AddBinding("FindControl('txtStreet1').Text", "Employee.MailingAddress.Street1"); + BindingManager.AddBinding("FindControl('txtStreet2').Text", "Employee.MailingAddress.Street2"); + BindingManager.AddBinding("FindControl('txtCity').Text", "Employee.MailingAddress.City"); + BindingManager.AddBinding("FindControl('txtState').Text", "Employee.MailingAddress.State"); + BindingManager.AddBinding("FindControl('txtPostalCode').Text", "Employee.MailingAddress.PostalCode"); + BindingManager.AddBinding("FindControl('txtCountry').Text", "Employee.MailingAddress.Country"); } protected void Page_Load(object sender, EventArgs e) diff --git a/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/DataBinding/EventHandling/Default.aspx b/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/DataBinding/EventHandling/Default.aspx index b513448c..74781fba 100644 --- a/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/DataBinding/EventHandling/Default.aspx +++ b/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/DataBinding/EventHandling/Default.aspx @@ -1,4 +1,4 @@ -<%@ Page Language="C#" EnableViewState="false" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="DataBinding_EventHandling_Default" %> +<%@ Page Language="C#" Debug="true" EnableViewState="false" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="DataBinding_EventHandling_Default" %> diff --git a/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/DataBinding/EventHandling/Default.aspx.cs b/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/DataBinding/EventHandling/Default.aspx.cs index 18614799..5e7a00a9 100644 --- a/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/DataBinding/EventHandling/Default.aspx.cs +++ b/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/DataBinding/EventHandling/Default.aspx.cs @@ -1,4 +1,5 @@ using System; +using System.Web.UI.WebControls; using Spring.DataBinding; /// @@ -22,8 +23,8 @@ public partial class DataBinding_EventHandling_Default : Spring.Web.UI.Page /// protected override void InitializeDataBindings() { - BindingManager.AddBinding("txtName.Text", "Name"); - BindingManager.AddBinding("lblName.Text", "Name", BindingDirection.TargetToSource); + BindingManager.AddBinding("FindControl('txtName').Text", "Name"); + BindingManager.AddBinding("FindControl('lblName').Text", "Name", BindingDirection.TargetToSource); } protected void Page_Load(object sender, EventArgs e) diff --git a/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/DataBinding/HelloWorld/Default.aspx.cs b/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/DataBinding/HelloWorld/Default.aspx.cs index b53707b3..638c485a 100644 --- a/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/DataBinding/HelloWorld/Default.aspx.cs +++ b/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/DataBinding/HelloWorld/Default.aspx.cs @@ -22,8 +22,8 @@ public partial class DataBinding_HelloWorld_Default : Spring.Web.UI.Page /// protected override void InitializeDataBindings() { - BindingManager.AddBinding("txtName.Text", "Name"); - BindingManager.AddBinding("lblName.Text", "Name", BindingDirection.TargetToSource); + BindingManager.AddBinding("FindControl('txtName').Text", "Name"); + BindingManager.AddBinding("FindControl('lblName').Text", "Name", BindingDirection.TargetToSource); } protected void Page_Load(object sender, EventArgs e) diff --git a/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/DataBinding/Lists/Default.aspx.cs b/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/DataBinding/Lists/Default.aspx.cs index ea80d961..d8bce27a 100644 --- a/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/DataBinding/Lists/Default.aspx.cs +++ b/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/DataBinding/Lists/Default.aspx.cs @@ -26,19 +26,19 @@ public partial class DataBinding_Lists_Default : Page /// protected override void InitializeDataBindings() { - BindingManager.AddBinding("txtId.Text", "Employee.Id"); - BindingManager.AddBinding("txtFirstName.Text", "Employee.FirstName"); + BindingManager.AddBinding("FindControl('txtId').Text", "Employee.Id"); + BindingManager.AddBinding("FindControl('txtFirstName').Text", "Employee.FirstName"); // this is rather verbose to show how it works // the formatter must convert between ListControl values and domain objects identified by these values (e.g. a key) IFormatter dsFormatter = new DataSourceItemFormatter("DataSource", "DataValueField"); // bind the lstHobbies control to Employee.Hobbies IList - MultipleSelectionListControlBinding listBinding = new MultipleSelectionListControlBinding("lstHobbies", "Employee.Hobbies", BindingDirection.Bidirectional, dsFormatter); + MultipleSelectionListControlBinding listBinding = new MultipleSelectionListControlBinding("FindControl('lstHobbies')", "Employee.Hobbies", BindingDirection.Bidirectional, dsFormatter); BindingManager.AddBinding(listBinding); // use simple name=value binding - BindingManager.AddBinding(new MultipleSelectionListControlBinding("lstFavoriteFood", "Employee.FavoriteFood", BindingDirection.Bidirectional, new NullFormatter())); + BindingManager.AddBinding(new MultipleSelectionListControlBinding("FindControl('lstFavoriteFood')", "Employee.FavoriteFood", BindingDirection.Bidirectional, new NullFormatter())); } protected override void OnInitializeControls(EventArgs e) diff --git a/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/DataBinding/NestedEmployeeInfo/EmployeeInfoEditor.ascx.cs b/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/DataBinding/NestedEmployeeInfo/EmployeeInfoEditor.ascx.cs index 7c78020a..6e1df6b6 100644 --- a/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/DataBinding/NestedEmployeeInfo/EmployeeInfoEditor.ascx.cs +++ b/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/DataBinding/NestedEmployeeInfo/EmployeeInfoEditor.ascx.cs @@ -18,22 +18,22 @@ public partial class EmployeeInfoEditor : Spring.Web.UI.UserControl /// protected override void InitializeDataBindings() { - BindingManager.AddBinding("txtId.Text", "Employee.Id") + BindingManager.AddBinding("FindControl('txtId').Text", "Employee.Id") .SetErrorMessage("ID has to be an integer", "id.errors", "summary"); - BindingManager.AddBinding("txtFirstName.Text", "Employee.FirstName"); - BindingManager.AddBinding("txtLastName.Text", "Employee.LastName"); - BindingManager.AddBinding("txtDOB.Text", "Employee.DateOfBirth") + BindingManager.AddBinding("FindControl('txtFirstName').Text", "Employee.FirstName"); + BindingManager.AddBinding("FindControl('txtLastName').Text", "Employee.LastName"); + BindingManager.AddBinding("FindControl('txtDOB').Text", "Employee.DateOfBirth") .SetErrorMessage("Invalid date value", "dob.errors", "summary"); - BindingManager.AddBinding("txtSalary.Text", "Employee.Salary", new CurrencyFormatter()) + BindingManager.AddBinding("FindControl('txtSalary').Text", "Employee.Salary", new CurrencyFormatter()) .SetErrorMessage("Salary must be a valid currency value.", "salary.errors", "summary"); - BindingManager.AddBinding("rbgGender.Value", "Employee.Gender"); - BindingManager.AddBinding("ddlAddressType.SelectedValue", "Employee.MailingAddress.AddressType"); - BindingManager.AddBinding("txtStreet1.Text", "Employee.MailingAddress.Street1"); - BindingManager.AddBinding("txtStreet2.Text", "Employee.MailingAddress.Street2"); - BindingManager.AddBinding("txtCity.Text", "Employee.MailingAddress.City"); - BindingManager.AddBinding("txtState.Text", "Employee.MailingAddress.State"); - BindingManager.AddBinding("txtPostalCode.Text", "Employee.MailingAddress.PostalCode"); - BindingManager.AddBinding("txtCountry.Text", "Employee.MailingAddress.Country"); + BindingManager.AddBinding("FindControl('rbgGender').Value", "Employee.Gender"); + BindingManager.AddBinding("FindControl('ddlAddressType').SelectedValue", "Employee.MailingAddress.AddressType"); + BindingManager.AddBinding("FindControl('txtStreet1').Text", "Employee.MailingAddress.Street1"); + BindingManager.AddBinding("FindControl('txtStreet2').Text", "Employee.MailingAddress.Street2"); + BindingManager.AddBinding("FindControl('txtCity').Text", "Employee.MailingAddress.City"); + BindingManager.AddBinding("FindControl('txtState').Text", "Employee.MailingAddress.State"); + BindingManager.AddBinding("FindControl('txtPostalCode').Text", "Employee.MailingAddress.PostalCode"); + BindingManager.AddBinding("FindControl('txtCountry').Text", "Employee.MailingAddress.Country"); } protected void btnSave_Click(object sender, EventArgs e) diff --git a/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/DataBinding/RobustEmployeeInfo/Default.aspx b/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/DataBinding/RobustEmployeeInfo/Default.aspx index 9b5ef98f..737bce8b 100644 --- a/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/DataBinding/RobustEmployeeInfo/Default.aspx +++ b/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/DataBinding/RobustEmployeeInfo/Default.aspx @@ -34,7 +34,7 @@ so you can see how Employee object was populated by the framework.

- + diff --git a/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/DataBinding/RobustEmployeeInfo/Default.aspx.cs b/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/DataBinding/RobustEmployeeInfo/Default.aspx.cs index a03a0b11..7866b1c4 100644 --- a/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/DataBinding/RobustEmployeeInfo/Default.aspx.cs +++ b/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/DataBinding/RobustEmployeeInfo/Default.aspx.cs @@ -22,22 +22,26 @@ public partial class DataBinding_RobustEmployeeInfo_Default : Spring.Web.UI.Page /// protected override void InitializeDataBindings() { - BindingManager.AddBinding("txtId.Text", "Employee.Id") + // the line below would also work in full trusted environments due to control members + // being generated as protected members by ASP.NET: + // BindingManager.AddBinding("txtId.Text", "Employee.Id") + + BindingManager.AddBinding("FindControl('txtId').Text", "Employee.Id") .SetErrorMessage("ID has to be an integer", "id.errors"); // send msg to "id.errors" provider - BindingManager.AddBinding("txtFirstName.Text", "Employee.FirstName"); - BindingManager.AddBinding("txtLastName.Text", "Employee.LastName"); - BindingManager.AddBinding("txtDOB.Text", "Employee.DateOfBirth") + BindingManager.AddBinding("FindControl('txtFirstName').Text", "Employee.FirstName"); + BindingManager.AddBinding("FindControl('txtLastName').Text", "Employee.LastName"); + BindingManager.AddBinding("FindControl('txtDOB').Text", "Employee.DateOfBirth") .SetErrorMessage("Invalid date value", "dob.errors"); - BindingManager.AddBinding("txtSalary.Text", "Employee.Salary", new CurrencyFormatter()) + BindingManager.AddBinding("FindControl('txtSalary').Text", "Employee.Salary", new CurrencyFormatter()) .SetErrorMessage("Salary must be a valid currency value.", "salary.errors"); - BindingManager.AddBinding("rbgGender.Value", "Employee.Gender"); - BindingManager.AddBinding("ddlAddressType.SelectedValue", "Employee.MailingAddress.AddressType"); - BindingManager.AddBinding("txtStreet1.Text", "Employee.MailingAddress.Street1"); - BindingManager.AddBinding("txtStreet2.Text", "Employee.MailingAddress.Street2"); - BindingManager.AddBinding("txtCity.Text", "Employee.MailingAddress.City"); - BindingManager.AddBinding("txtState.Text", "Employee.MailingAddress.State"); - BindingManager.AddBinding("txtPostalCode.Text", "Employee.MailingAddress.PostalCode"); - BindingManager.AddBinding("txtCountry.Text", "Employee.MailingAddress.Country"); + BindingManager.AddBinding("FindControl('rbgGender').Value", "Employee.Gender"); + BindingManager.AddBinding("FindControl('ddlAddressType').SelectedValue", "Employee.MailingAddress.AddressType"); + BindingManager.AddBinding("FindControl('txtStreet1').Text", "Employee.MailingAddress.Street1"); + BindingManager.AddBinding("FindControl('txtStreet2').Text", "Employee.MailingAddress.Street2"); + BindingManager.AddBinding("FindControl('txtCity').Text", "Employee.MailingAddress.City"); + BindingManager.AddBinding("FindControl('txtState').Text", "Employee.MailingAddress.State"); + BindingManager.AddBinding("FindControl('txtPostalCode').Text", "Employee.MailingAddress.PostalCode"); + BindingManager.AddBinding("FindControl('txtCountry').Text", "Employee.MailingAddress.Country"); } protected void Page_Load(object sender, EventArgs e) diff --git a/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/Navigation/Default.aspx b/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/Navigation/Default.aspx index 9c0aaf0b..338a65e8 100644 --- a/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/Navigation/Default.aspx +++ b/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/Navigation/Default.aspx @@ -7,7 +7,7 @@ Spring.Web allows for "symbolic" names for navigation targets and navigate to such a target by calling SetResult( symbolicName ) on the page object.

- +
Employee ID:
diff --git a/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/Web.Config b/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/Web.Config index 909cd73b..797b7f55 100644 --- a/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/Web.Config +++ b/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/Web.Config @@ -2,11 +2,11 @@ -
-
+
+
-
+
@@ -18,6 +18,13 @@ + + + + + + + @@ -31,9 +38,9 @@ --> - - - + + + diff --git a/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/web_mediumtrust.config b/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/web_mediumtrust.config new file mode 100644 index 00000000..0cae3044 --- /dev/null +++ b/examples/Spring/Spring.WebQuickStart/src/Spring.WebQuickStart.2005/web_mediumtrust.config @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Spring/Spring.Core/AssemblyInfo.cs b/src/Spring/Spring.Core/AssemblyInfo.cs index 7282cf2a..74041e7b 100644 --- a/src/Spring/Spring.Core/AssemblyInfo.cs +++ b/src/Spring/Spring.Core/AssemblyInfo.cs @@ -18,9 +18,10 @@ #endregion +using System; using System.Reflection; using System.Runtime.InteropServices; -using System.Security.Permissions; +using System.Security; [assembly: ComVisible(false)] [assembly: AssemblyTitle("Spring.Core")] @@ -29,7 +30,24 @@ using System.Security.Permissions; // // Security Permissions // -// we need full, unrestricted access to reflection metadata... -[assembly: ReflectionPermission(SecurityAction.RequestMinimum, Unrestricted=true)] +// we need full, unrestricted access to reflection metadata... +//[assembly: ReflectionPermission(SecurityAction.RequestMinimum, Unrestricted = true)] //[assembly: AssemblyKeyFile(@"C:\users\aseovic\projects\OpenSource\Spring.Net\Spring.Net.PrivateKey.keys")] -//[assembly: AssemblyKeyFile(@"C:\projects\Spring.Net\Spring.Net.snk")] \ No newline at end of file +//[assembly: AssemblyKeyFile(@"C:\projects\Spring.Net\Spring.Net.snk")] +[assembly: AllowPartiallyTrustedCallers] + +[assembly: SecurityCritical] + +#if NET_1_0 || NET_1_1 +namespace System.Security +{ + /// + /// + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Method)] + internal class SecurityCriticalAttribute : Attribute + { } + [AttributeUsage(AttributeTargets.Method)] + internal class SecurityTreatAsSafeAttribute : Attribute + { } +} +#endif diff --git a/src/Spring/Spring.Core/Core/IO/ResourceHandlerRegistry.cs b/src/Spring/Spring.Core/Core/IO/ResourceHandlerRegistry.cs index fcf3698c..20ff9f92 100644 --- a/src/Spring/Spring.Core/Core/IO/ResourceHandlerRegistry.cs +++ b/src/Spring/Spring.Core/Core/IO/ResourceHandlerRegistry.cs @@ -1,5 +1,5 @@ -#region License - +#region License + /* * Copyright 2002-2004 the original author or authors. * @@ -14,273 +14,277 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - */ - -#endregion - -using System; -using System.Collections; -using System.Reflection; - -using Spring.Context.Support; -using Spring.Core.TypeResolution; -using Spring.Util; -using Spring.Reflection.Dynamic; - -namespace Spring.Core.IO -{ - /// - /// Registry class that allows users to register and retrieve protocol handlers. - /// - /// - /// - /// Resource handler is an implementation of interface - /// that should be used to process resources with the specified protocol. - /// - /// - /// They are used throughout the framework to access resources from various - /// sources. For example, application context loads object definitions from the resources - /// that are processed using one of the registered resource handlers. - /// - /// Following resource handlers are registered by default: - /// - /// - /// Protocol - /// Handler Type - /// Description - /// - /// - /// config - /// - /// Resolves the resources by loading specified configuration section from the standard .NET config file. - /// - /// - /// file - /// - /// Resolves filesystem resources. - /// - /// - /// http - /// - /// Resolves remote web resources. - /// - /// - /// https - /// - /// Resolves remote web resources via HTTPS. - /// - /// - /// ftp - /// - /// Resolves ftp resources. - /// - /// - /// assembly - /// - /// Resolves resources that are embedded into an assembly. - /// - /// - /// web - /// Spring.Core.IO.WebResource, Spring.Web* - /// Resolves resources relative to the web application's virtual directory. - /// - /// - /// * only available in web applications. - /// - /// Users can create and register their own protocol handlers by implementing interface - /// and mapping custom protocol name to that implementation. See for details - /// on how to register custom protocol handler. - /// - /// - /// Aleksandar Seovic - public class ResourceHandlerRegistry - { - /// - /// Name of the .Net config section that contains definitions - /// for custom resource handlers. - /// - private const string ResourcesSectionName = "spring/resourceHandlers"; - - private static IDictionary resourceHandlers = new Hashtable(); - - /// - /// Registers standard and user-configured resource handlers. - /// - static ResourceHandlerRegistry() - { - lock (resourceHandlers.SyncRoot) - { - RegisterResourceHandler("config", typeof(ConfigSectionResource)); - RegisterResourceHandler("file", typeof(FileSystemResource)); - RegisterResourceHandler("http", typeof(UrlResource)); - RegisterResourceHandler("https", typeof(UrlResource)); -#if NET_2_0 - RegisterResourceHandler("ftp", typeof(UrlResource)); -#endif - RegisterResourceHandler("assembly", typeof(AssemblyResource)); - - // register custom resource handlers - ConfigurationUtils.GetSection(ResourcesSectionName); - } - } - - /// - /// Returns resource handler for the specified protocol name. - /// - /// - /// - /// This method returns object that should be used - /// to create an instance of the -derived type by passing - /// resource location as a parameter. - /// - /// - /// Name of the protocol to get the handler for. - /// Resource handler constructor for the specified protocol name. - /// If is null. - public static IDynamicConstructor GetResourceHandler(string protocolName) - { - AssertUtils.ArgumentNotNull(protocolName, "protocolName"); - return (IDynamicConstructor) resourceHandlers[protocolName]; - } - - /// - /// Returns true if a handler is registered for the specified protocol, - /// false otherwise. - /// - /// Name of the protocol. - /// - /// true if a handler is registered for the specified protocol, false otherwise. - /// - /// If is null. - public static bool IsHandlerRegistered(string protocolName) - { - return resourceHandlers.Contains(protocolName); - } - - /// - /// Registers resource handler and maps it to the specified protocol name. - /// - /// - ///

- /// If the mapping already exists, the existing mapping will be - /// silently overwritten with the new mapping. - ///

- ///
- /// - /// The protocol to add (or override). - /// - /// - /// The type name of the concrete implementation of the - /// interface that will handle - /// the specified protocol. - /// - /// - /// If the supplied is - /// or contains only whitespace character(s); or - /// if the supplied is - /// . - /// - /// - /// If the supplied is not a - /// that derives from the - /// interface; or (having passed - /// this first check), the supplied - /// does not expose a constructor that takes a single - /// parameter. - /// - public static void RegisterResourceHandler(string protocolName, string handlerTypeName) - { - AssertUtils.ArgumentHasText(protocolName, "protocolName"); - AssertUtils.ArgumentHasText(handlerTypeName, "handlerTypeName"); - - Type handlerType = TypeResolutionUtils.ResolveType(handlerTypeName); - RegisterResourceHandler(protocolName, handlerType); - } - - /// - /// Registers resource handler and maps it to the specified protocol name. - /// - /// - ///

- /// If the mapping already exists, the existing mapping will be - /// silently overwritten with the new mapping. - ///

- ///
- /// - /// The protocol to add (or override). - /// - /// - /// The concrete implementation of the - /// interface that will handle - /// the specified protocol. - /// - /// - /// If the supplied is - /// or contains only whitespace character(s); or - /// if the supplied is - /// . - /// - /// - /// If the supplied is not a - /// that derives from the - /// interface; or (having passed - /// this first check), the supplied - /// does not expose a constructor that takes a single - /// parameter. - /// - public static void RegisterResourceHandler(string protocolName, Type handlerType) - { - #region Sanity Checks - - AssertUtils.ArgumentHasText(protocolName, "protocolName"); - AssertUtils.ArgumentNotNull(handlerType, "handlerType"); - if (!typeof(IResource).IsAssignableFrom(handlerType)) - { - throw new ArgumentException( - string.Format("[{0}] does not implement [{1}] interface (it must).", handlerType.FullName, typeof(IResource).FullName)); - } - - #endregion - - lock (resourceHandlers.SyncRoot) - { -#if NET_2_0 - // register generic uri parser for this scheme - if (!UriParser.IsKnownScheme(protocolName)) + */ + +#endregion + +using System; +using System.Collections; +using System.Reflection; +using System.Security; +using System.Security.Permissions; +using Spring.Context.Support; +using Spring.Core.TypeResolution; +using Spring.Util; +using Spring.Reflection.Dynamic; + +namespace Spring.Core.IO +{ + /// + /// Registry class that allows users to register and retrieve protocol handlers. + /// + /// + /// + /// Resource handler is an implementation of interface + /// that should be used to process resources with the specified protocol. + /// + /// + /// They are used throughout the framework to access resources from various + /// sources. For example, application context loads object definitions from the resources + /// that are processed using one of the registered resource handlers. + /// + /// Following resource handlers are registered by default: + /// + /// + /// Protocol + /// Handler Type + /// Description + /// + /// + /// config + /// + /// Resolves the resources by loading specified configuration section from the standard .NET config file. + /// + /// + /// file + /// + /// Resolves filesystem resources. + /// + /// + /// http + /// + /// Resolves remote web resources. + /// + /// + /// https + /// + /// Resolves remote web resources via HTTPS. + /// + /// + /// ftp + /// + /// Resolves ftp resources. + /// + /// + /// assembly + /// + /// Resolves resources that are embedded into an assembly. + /// + /// + /// web + /// Spring.Core.IO.WebResource, Spring.Web* + /// Resolves resources relative to the web application's virtual directory. + /// + /// + /// * only available in web applications. + /// + /// Users can create and register their own protocol handlers by implementing interface + /// and mapping custom protocol name to that implementation. See for details + /// on how to register custom protocol handler. + /// + /// + /// Aleksandar Seovic + public class ResourceHandlerRegistry + { + /// + /// Name of the .Net config section that contains definitions + /// for custom resource handlers. + /// + private const string ResourcesSectionName = "spring/resourceHandlers"; + + private static IDictionary resourceHandlers = new Hashtable(); + + /// + /// Registers standard and user-configured resource handlers. + /// + static ResourceHandlerRegistry() + { + lock (resourceHandlers.SyncRoot) + { + RegisterResourceHandler("config", typeof(ConfigSectionResource)); + RegisterResourceHandler("file", typeof(FileSystemResource)); + RegisterResourceHandler("http", typeof(UrlResource)); + RegisterResourceHandler("https", typeof(UrlResource)); +#if NET_2_0 + RegisterResourceHandler("ftp", typeof(UrlResource)); +#endif + RegisterResourceHandler("assembly", typeof(AssemblyResource)); + + // register custom resource handlers + ConfigurationUtils.GetSection(ResourcesSectionName); + } + } + + /// + /// Returns resource handler for the specified protocol name. + /// + /// + /// + /// This method returns object that should be used + /// to create an instance of the -derived type by passing + /// resource location as a parameter. + /// + /// + /// Name of the protocol to get the handler for. + /// Resource handler constructor for the specified protocol name. + /// If is null. + public static IDynamicConstructor GetResourceHandler(string protocolName) + { + AssertUtils.ArgumentNotNull(protocolName, "protocolName"); + return (IDynamicConstructor)resourceHandlers[protocolName]; + } + + /// + /// Returns true if a handler is registered for the specified protocol, + /// false otherwise. + /// + /// Name of the protocol. + /// + /// true if a handler is registered for the specified protocol, false otherwise. + /// + /// If is null. + public static bool IsHandlerRegistered(string protocolName) + { + return resourceHandlers.Contains(protocolName); + } + + /// + /// Registers resource handler and maps it to the specified protocol name. + /// + /// + ///

+ /// If the mapping already exists, the existing mapping will be + /// silently overwritten with the new mapping. + ///

+ ///
+ /// + /// The protocol to add (or override). + /// + /// + /// The type name of the concrete implementation of the + /// interface that will handle + /// the specified protocol. + /// + /// + /// If the supplied is + /// or contains only whitespace character(s); or + /// if the supplied is + /// . + /// + /// + /// If the supplied is not a + /// that derives from the + /// interface; or (having passed + /// this first check), the supplied + /// does not expose a constructor that takes a single + /// parameter. + /// + public static void RegisterResourceHandler(string protocolName, string handlerTypeName) + { + AssertUtils.ArgumentHasText(protocolName, "protocolName"); + AssertUtils.ArgumentHasText(handlerTypeName, "handlerTypeName"); + + Type handlerType = TypeResolutionUtils.ResolveType(handlerTypeName); + RegisterResourceHandler(protocolName, handlerType); + } + + /// + /// Registers resource handler and maps it to the specified protocol name. + /// + /// + ///

+ /// If the mapping already exists, the existing mapping will be + /// silently overwritten with the new mapping. + ///

+ ///
+ /// + /// The protocol to add (or override). + /// + /// + /// The concrete implementation of the + /// interface that will handle + /// the specified protocol. + /// + /// + /// If the supplied is + /// or contains only whitespace character(s); or + /// if the supplied is + /// . + /// + /// + /// If the supplied is not a + /// that derives from the + /// interface; or (having passed + /// this first check), the supplied + /// does not expose a constructor that takes a single + /// parameter. + /// + public static void RegisterResourceHandler(string protocolName, Type handlerType) + { + #region Sanity Checks + + AssertUtils.ArgumentHasText(protocolName, "protocolName"); + AssertUtils.ArgumentNotNull(handlerType, "handlerType"); + if (!typeof(IResource).IsAssignableFrom(handlerType)) + { + throw new ArgumentException( + string.Format("[{0}] does not implement [{1}] interface (it must).", handlerType.FullName, typeof(IResource).FullName)); + } + + #endregion + + lock (resourceHandlers.SyncRoot) + { +#if NET_2_0 + SecurityCritical.ExecutePrivileged( new SecurityPermission(SecurityPermissionFlag.Infrastructure), delegate { - UriParser.Register(new TolerantUriParser(), protocolName, 0); - } -#endif - IDynamicConstructor ctor = GetResourceConstructor(handlerType); - resourceHandlers[protocolName] = ctor; - } - } - -#if NET_2_0 + // register generic uri parser for this scheme + if (!UriParser.IsKnownScheme(protocolName)) + { + UriParser.Register(new TolerantUriParser(), protocolName, 0); + } + }); +#endif + IDynamicConstructor ctor = GetResourceConstructor(handlerType); + resourceHandlers[protocolName] = ctor; + } + } + +#if NET_2_0 /// /// Allows to create any arbitrary Url format - /// - private class TolerantUriParser : GenericUriParser + /// + private class TolerantUriParser : GenericUriParser { private const GenericUriParserOptions DefaultOptions = GenericUriParserOptions.Default - |GenericUriParserOptions.GenericAuthority - |GenericUriParserOptions.AllowEmptyAuthority; + | GenericUriParserOptions.GenericAuthority + | GenericUriParserOptions.AllowEmptyAuthority; - public TolerantUriParser() + public TolerantUriParser() : base(DefaultOptions) - {} - } -#endif - - private static IDynamicConstructor GetResourceConstructor(Type handlerType) - { - ConstructorInfo ctor = handlerType.GetConstructor(new Type[] {typeof(string)}); - if (ctor == null) - { - throw new ArgumentException( - string.Format("[{0}] does not have a constructor that takes a single string as an argument (it must).", handlerType.FullName)); - } - return DynamicConstructor.Create(ctor); - } - } + { } + } +#endif + + private static IDynamicConstructor GetResourceConstructor(Type handlerType) + { + ConstructorInfo ctor = handlerType.GetConstructor(new Type[] { typeof(string) }); + if (ctor == null) + { + throw new ArgumentException( + string.Format("[{0}] does not have a constructor that takes a single string as an argument (it must).", handlerType.FullName)); + } + return new SafeConstructor(ctor); + } + } } \ No newline at end of file diff --git a/src/Spring/Spring.Core/DataBinding/AbstractSimpleBinding.cs b/src/Spring/Spring.Core/DataBinding/AbstractSimpleBinding.cs index e3a02573..f87f6d84 100644 --- a/src/Spring/Spring.Core/DataBinding/AbstractSimpleBinding.cs +++ b/src/Spring/Spring.Core/DataBinding/AbstractSimpleBinding.cs @@ -1,5 +1,7 @@ using System; using System.Collections; +using System.Reflection; +using Common.Logging; using Spring.Globalization; using Spring.Validation; @@ -13,6 +15,7 @@ namespace Spring.DataBinding { #region Fields + private readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private IFormatter formatter; #endregion @@ -132,8 +135,9 @@ namespace Spring.DataBinding { DoBindTargetToSource(source, target, variables); } - catch (Exception) + catch (Exception ex) { + log.Warn(string.Format("Failed binding[{0}]:{1}", this.Id, ex)); if (!SetInvalid(validationErrors)) throw; } } diff --git a/src/Spring/Spring.Core/Expressions/IndexerNode.cs b/src/Spring/Spring.Core/Expressions/IndexerNode.cs index e1ce7367..7bf94bec 100644 --- a/src/Spring/Spring.Core/Expressions/IndexerNode.cs +++ b/src/Spring/Spring.Core/Expressions/IndexerNode.cs @@ -273,16 +273,21 @@ namespace Spring.Expressions { if (indexer == null) { + Type contextType = context.GetType(); Type[] argTypes = ReflectionUtils.GetTypes(indices); - PropertyInfo indexerProperty = context.GetType().GetProperty("Item", BINDING_FLAGS, null, null, argTypes, null); + string defaultMember = "Item"; + object[] atts = contextType.GetCustomAttributes(typeof(DefaultMemberAttribute), true); + if (atts != null && atts.Length > 0) + { + defaultMember = ((DefaultMemberAttribute) atts[0]).MemberName; + } + PropertyInfo indexerProperty = contextType.GetProperty(defaultMember, BINDING_FLAGS, null, null, argTypes, null); if (indexerProperty == null) { throw new ArgumentException("Indexer property with specified number and types of arguments does not exist."); } - else - { - indexer = new SafeProperty(indexerProperty); - } + + indexer = new SafeProperty(indexerProperty); } } } diff --git a/src/Spring/Spring.Core/Reflection/Dynamic/DynamicReflectionManager.cs b/src/Spring/Spring.Core/Reflection/Dynamic/DynamicReflectionManager.cs index 1a847528..214142e4 100644 --- a/src/Spring/Spring.Core/Reflection/Dynamic/DynamicReflectionManager.cs +++ b/src/Spring/Spring.Core/Reflection/Dynamic/DynamicReflectionManager.cs @@ -25,6 +25,9 @@ using System.Collections; using System.Diagnostics; using System.Reflection; using System.Reflection.Emit; +using System.Runtime.CompilerServices; +using System.Security; +using System.Security.Permissions; using Spring.Util; #if NET_2_0 @@ -40,14 +43,14 @@ namespace Spring.Reflection.Dynamic /// /// the target instance when calling an instance method /// the value return by the Get method - public delegate object FieldGetterDelegate( object target ); + public delegate object FieldGetterDelegate(object target); /// /// Represents a Set method /// /// the target instance when calling an instance method /// the value to be set - public delegate void FieldSetterDelegate( object target, object value ); + public delegate void FieldSetterDelegate(object target, object value); /// /// Represents an Indexer Get method @@ -55,7 +58,7 @@ namespace Spring.Reflection.Dynamic /// the target instance when calling an instance method /// /// the value return by the Get method - public delegate object PropertyGetterDelegate( object target, params object[] index ); + public delegate object PropertyGetterDelegate(object target, params object[] index); /// /// Represents a Set method @@ -63,7 +66,7 @@ namespace Spring.Reflection.Dynamic /// the target instance when calling an instance method /// the value to be set /// - public delegate void PropertySetterDelegate( object target, object value, params object[] index ); + public delegate void PropertySetterDelegate(object target, object value, params object[] index); /// /// Represents a method @@ -71,35 +74,35 @@ namespace Spring.Reflection.Dynamic /// the target instance when calling an instance method /// arguments to be passed to the method /// the value return by the method. null when calling a void method - public delegate object FunctionDelegate( object target, params object[] args ); + public delegate object FunctionDelegate(object target, params object[] args); /// /// Represents a constructor /// /// arguments to be passed to the method /// the new object instance - public delegate object ConstructorDelegate( params object[] args ); + public delegate object ConstructorDelegate(params object[] args); /// /// Represents a callback method used to create an from a instance. /// - internal delegate IDynamicProperty CreatePropertyCallback( PropertyInfo property ); + internal delegate IDynamicProperty CreatePropertyCallback(PropertyInfo property); /// /// Represents a callback method used to create an from a instance. /// - internal delegate IDynamicField CreateFieldCallback( FieldInfo property ); + internal delegate IDynamicField CreateFieldCallback(FieldInfo property); /// /// Represents a callback method used to create an from a instance. /// - internal delegate IDynamicMethod CreateMethodCallback( MethodInfo method ); + internal delegate IDynamicMethod CreateMethodCallback(MethodInfo method); /// /// Represents a callback method used to create an from a instance. /// - internal delegate IDynamicConstructor CreateConstructorCallback( ConstructorInfo constructor ); + internal delegate IDynamicConstructor CreateConstructorCallback(ConstructorInfo constructor); /// /// Represents a callback method used to create an from a instance. /// - internal delegate IDynamicIndexer CreateIndexerCallback( PropertyInfo indexer ); + internal delegate IDynamicIndexer CreateIndexerCallback(PropertyInfo indexer); /// /// Allows easy access to existing and creation of new dynamic relection members. @@ -156,14 +159,14 @@ namespace Spring.Reflection.Dynamic /// The base name to use for the reflection type name. /// /// The type builder to use. - internal static TypeBuilder CreateTypeBuilder( string name ) + internal static TypeBuilder CreateTypeBuilder(string name) { // Generates type name - string typeName = String.Format( "{0}.{1}_{2}", - ASSEMBLY_NAME, name, Guid.NewGuid().ToString( "N" ) ); + string typeName = String.Format("{0}.{1}_{2}", + ASSEMBLY_NAME, name, Guid.NewGuid().ToString("N")); - ModuleBuilder module = DynamicCodeManager.GetModuleBuilder( ASSEMBLY_NAME ); - return module.DefineType( typeName, TYPE_ATTRIBUTES ); + ModuleBuilder module = DynamicCodeManager.GetModuleBuilder(ASSEMBLY_NAME); + return module.DefineType(typeName, TYPE_ATTRIBUTES); } /// @@ -172,14 +175,14 @@ namespace Spring.Reflection.Dynamic /// Property to look up. /// callback function that will be called to create the dynamic property /// An for the given property info. - internal static IDynamicProperty GetDynamicProperty( PropertyInfo property, CreatePropertyCallback createCallback ) + internal static IDynamicProperty GetDynamicProperty(PropertyInfo property, CreatePropertyCallback createCallback) { lock (propertyCache.SyncRoot) { IDynamicProperty dynamicProperty = (IDynamicProperty)propertyCache[property]; if (dynamicProperty == null) { - dynamicProperty = createCallback( property ); + dynamicProperty = createCallback(property); propertyCache[property] = dynamicProperty; } return dynamicProperty; @@ -192,14 +195,14 @@ namespace Spring.Reflection.Dynamic /// Field to look up. /// callback function that will be called to create the dynamic field /// An for the given field info. - internal static IDynamicField GetDynamicField( FieldInfo field, CreateFieldCallback createCallback ) + internal static IDynamicField GetDynamicField(FieldInfo field, CreateFieldCallback createCallback) { lock (fieldCache.SyncRoot) { IDynamicField dynamicField = (IDynamicField)fieldCache[field]; if (dynamicField == null) { - dynamicField = createCallback( field ); + dynamicField = createCallback(field); fieldCache[field] = dynamicField; } return dynamicField; @@ -212,14 +215,14 @@ namespace Spring.Reflection.Dynamic /// Indexer to look up. /// callback function that will be called to create the dynamic indexer /// An for the given indexer. - internal static IDynamicIndexer GetDynamicIndexer( PropertyInfo indexer, CreateIndexerCallback createCallback ) + internal static IDynamicIndexer GetDynamicIndexer(PropertyInfo indexer, CreateIndexerCallback createCallback) { lock (indexerCache.SyncRoot) { IDynamicIndexer dynamicIndexer = (IDynamicIndexer)indexerCache[indexer]; if (dynamicIndexer == null) { - dynamicIndexer = createCallback( indexer ); + dynamicIndexer = createCallback(indexer); indexerCache[indexer] = dynamicIndexer; } return dynamicIndexer; @@ -232,14 +235,14 @@ namespace Spring.Reflection.Dynamic /// Method to look up. /// callback function that will be called to create the dynamic method /// An for the given method. - internal static IDynamicMethod GetDynamicMethod( MethodInfo method, CreateMethodCallback createCallback ) + internal static IDynamicMethod GetDynamicMethod(MethodInfo method, CreateMethodCallback createCallback) { lock (methodCache.SyncRoot) { IDynamicMethod dynamicMethod = (IDynamicMethod)methodCache[method]; if (dynamicMethod == null) { - dynamicMethod = createCallback( method ); + dynamicMethod = createCallback(method); methodCache[method] = dynamicMethod; } return dynamicMethod; @@ -252,14 +255,14 @@ namespace Spring.Reflection.Dynamic /// Constructor to look up. /// callback function that will be called to create the dynamic constructor /// An for the given constructor. - internal static IDynamicConstructor GetDynamicConstructor( ConstructorInfo constructor, CreateConstructorCallback createCallback ) + internal static IDynamicConstructor GetDynamicConstructor(ConstructorInfo constructor, CreateConstructorCallback createCallback) { lock (constructorCache.SyncRoot) { IDynamicConstructor dynamicConstructor = (IDynamicConstructor)constructorCache[constructor]; if (dynamicConstructor == null) { - dynamicConstructor = createCallback( constructor ); + dynamicConstructor = createCallback(constructor); constructorCache[constructor] = dynamicConstructor; } return dynamicConstructor; @@ -270,10 +273,10 @@ namespace Spring.Reflection.Dynamic /// Saves dynamically generated assembly to disk. /// Can only be called in DEBUG mode, per ConditionalAttribute rules. /// - [Conditional( "DEBUG_DYNAMIC" )] + [Conditional("DEBUG_DYNAMIC")] public static void SaveAssembly() { - DynamicCodeManager.SaveAssembly( ASSEMBLY_NAME ); + DynamicCodeManager.SaveAssembly(ASSEMBLY_NAME); } #endregion @@ -284,14 +287,16 @@ namespace Spring.Reflection.Dynamic /// /// the field to create the delegate for /// a delegate that can be used to read the field - public static FieldGetterDelegate CreateFieldGetter( FieldInfo fieldInfo ) + public static FieldGetterDelegate CreateFieldGetter(FieldInfo fieldInfo) { - AssertUtils.ArgumentNotNull( fieldInfo, "You cannot create a delegate for a null value." ); + AssertUtils.ArgumentNotNull(fieldInfo, "You cannot create a delegate for a null value."); - System.Reflection.Emit.DynamicMethod dmGetter = new System.Reflection.Emit.DynamicMethod( "getter", typeof( object ), new Type[] { typeof( object ) }, fieldInfo.DeclaringType.Module, true ); + bool skipVisibility = !IsPublic(fieldInfo); + Type[] argumentTypes = new Type[] { typeof(object) }; + System.Reflection.Emit.DynamicMethod dmGetter = CreateDynamicMethod("get_" + fieldInfo.Name, typeof(object), argumentTypes, fieldInfo, skipVisibility); ILGenerator il = dmGetter.GetILGenerator(); - EmitFieldGetter( il, fieldInfo, false ); - return (FieldGetterDelegate)dmGetter.CreateDelegate( typeof( FieldGetterDelegate ) ); + EmitFieldGetter(il, fieldInfo, false); + return (FieldGetterDelegate)dmGetter.CreateDelegate(typeof(FieldGetterDelegate)); } /// @@ -303,14 +308,15 @@ namespace Spring.Reflection.Dynamic /// If the field's returns true, the returned method /// will throw an when called. /// - public static FieldSetterDelegate CreateFieldSetter( FieldInfo fieldInfo ) + public static FieldSetterDelegate CreateFieldSetter(FieldInfo fieldInfo) { - AssertUtils.ArgumentNotNull( fieldInfo, "You cannot create a delegate for a null value." ); + AssertUtils.ArgumentNotNull(fieldInfo, "You cannot create a delegate for a null value."); - System.Reflection.Emit.DynamicMethod dmSetter = new System.Reflection.Emit.DynamicMethod( "setter", null, new Type[] { typeof( object ), typeof( object ) }, fieldInfo.DeclaringType.Module, true ); + bool skipVisibility = !IsPublic(fieldInfo); + System.Reflection.Emit.DynamicMethod dmSetter = CreateDynamicMethod("set_" + fieldInfo.Name, null, new Type[] { typeof(object), typeof(object) }, fieldInfo, skipVisibility); ILGenerator il = dmSetter.GetILGenerator(); - EmitFieldSetter( il, fieldInfo, false ); - return (FieldSetterDelegate)dmSetter.CreateDelegate( typeof( FieldSetterDelegate ) ); + EmitFieldSetter(il, fieldInfo, false); + return (FieldSetterDelegate)dmSetter.CreateDelegate(typeof(FieldSetterDelegate)); } /// @@ -322,14 +328,16 @@ namespace Spring.Reflection.Dynamic /// If the property's returns false, the returned method /// will throw an when called. /// - public static PropertyGetterDelegate CreatePropertyGetter( PropertyInfo propertyInfo ) + public static PropertyGetterDelegate CreatePropertyGetter(PropertyInfo propertyInfo) { - AssertUtils.ArgumentNotNull( propertyInfo, "You cannot create a delegate for a null value." ); + AssertUtils.ArgumentNotNull(propertyInfo, "You cannot create a delegate for a null value."); - NetDynamicMethod dm = new NetDynamicMethod( string.Empty, typeof( object ), new Type[] { typeof( object ), typeof( object[] ) }, propertyInfo.DeclaringType.Module, true ); + MethodInfo getMethod = propertyInfo.GetGetMethod(); + bool skipVisibility = (null == getMethod || !IsPublic(getMethod)); // getter is public + NetDynamicMethod dm = CreateDynamicMethod("get_" + propertyInfo.Name, typeof(object), new Type[] { typeof(object), typeof(object[]) }, propertyInfo, skipVisibility); ILGenerator il = dm.GetILGenerator(); - EmitPropertyGetter( il, propertyInfo, false ); - return (PropertyGetterDelegate)dm.CreateDelegate( typeof( PropertyGetterDelegate ) ); + EmitPropertyGetter(il, propertyInfo, false); + return (PropertyGetterDelegate)dm.CreateDelegate(typeof(PropertyGetterDelegate)); } /// @@ -341,14 +349,17 @@ namespace Spring.Reflection.Dynamic /// If the property's returns false, the returned method /// will throw an when called. /// - public static PropertySetterDelegate CreatePropertySetter( PropertyInfo propertyInfo ) + public static PropertySetterDelegate CreatePropertySetter(PropertyInfo propertyInfo) { - AssertUtils.ArgumentNotNull( propertyInfo, "You cannot create a delegate for a null value." ); + AssertUtils.ArgumentNotNull(propertyInfo, "You cannot create a delegate for a null value."); - NetDynamicMethod dm = new NetDynamicMethod( string.Empty, null, new Type[] { typeof( object ), typeof( object ), typeof( object[] ) }, propertyInfo.DeclaringType.Module, true ); + MethodInfo setMethod = propertyInfo.GetSetMethod(); + bool skipVisibility = (null == setMethod || !IsPublic(setMethod)); // setter is public + Type[] argumentTypes = new Type[] { typeof(object), typeof(object), typeof(object[]) }; + NetDynamicMethod dm = CreateDynamicMethod("set_" + propertyInfo.Name, null, argumentTypes, propertyInfo, skipVisibility); ILGenerator il = dm.GetILGenerator(); - EmitPropertySetter( il, propertyInfo, false ); - return (PropertySetterDelegate)dm.CreateDelegate( typeof( PropertySetterDelegate ) ); + EmitPropertySetter(il, propertyInfo, false); + return (PropertySetterDelegate)dm.CreateDelegate(typeof(PropertySetterDelegate)); } /// @@ -356,14 +367,15 @@ namespace Spring.Reflection.Dynamic /// /// the method to create the delegate for /// a delegate that can be used to invoke the method. - public static FunctionDelegate CreateMethod( MethodInfo methodInfo ) + public static FunctionDelegate CreateMethod(MethodInfo methodInfo) { - AssertUtils.ArgumentNotNull( methodInfo, "You cannot create a delegate for a null value." ); + AssertUtils.ArgumentNotNull(methodInfo, "You cannot create a delegate for a null value."); - NetDynamicMethod dm = new NetDynamicMethod( string.Empty, typeof( object ), new Type[] { typeof( object ), typeof( object[] ) }, methodInfo.DeclaringType.Module, true ); + bool skipVisibility = !IsPublic(methodInfo); + NetDynamicMethod dm = CreateDynamicMethod(methodInfo.Name, typeof(object), new Type[] { typeof(object), typeof(object[]) }, methodInfo, skipVisibility); ILGenerator il = dm.GetILGenerator(); - EmitInvokeMethod( il, methodInfo, false ); - return (FunctionDelegate)dm.CreateDelegate( typeof( FunctionDelegate ) ); + EmitInvokeMethod(il, methodInfo, false); + return (FunctionDelegate)dm.CreateDelegate(typeof(FunctionDelegate)); } /// @@ -371,45 +383,140 @@ namespace Spring.Reflection.Dynamic /// ///the constructor to create the delegate for ///delegate that can be used to invoke the constructor. - public static ConstructorDelegate CreateConstructor(ConstructorInfo constructorInfo) + public static ConstructorDelegate CreateConstructor(ConstructorInfo constructorInfo) { - AssertUtils.ArgumentNotNull(constructorInfo, "You cannot create a dynamic constructor for a null value."); + AssertUtils.ArgumentNotNull(constructorInfo, "You cannot create a dynamic constructor for a null value."); - System.Reflection.Emit.DynamicMethod dmGetter = new System.Reflection.Emit.DynamicMethod( string.Empty, typeof( object ), new Type[] { typeof( object[] ) }, constructorInfo.DeclaringType.Module, true ); + bool skipVisibility = !IsPublic(constructorInfo); + System.Reflection.Emit.DynamicMethod dmGetter; + Type[] argumentTypes = new Type[] { typeof(object[]) }; + dmGetter = CreateDynamicMethod(constructorInfo.Name, typeof(object), argumentTypes, constructorInfo, skipVisibility); ILGenerator il = dmGetter.GetILGenerator(); - EmitInvokeConstructor( il, constructorInfo, false ); - ConstructorDelegate ctor = (ConstructorDelegate)dmGetter.CreateDelegate( typeof( ConstructorDelegate ) ); + EmitInvokeConstructor(il, constructorInfo, false); + ConstructorDelegate ctor = (ConstructorDelegate)dmGetter.CreateDelegate(typeof(ConstructorDelegate)); return ctor; } + + /// + /// Creates a instance with the highest possible code access security. + /// + /// + /// If allowed by security policy, associates the method with the s declaring type. + /// Otherwise associates the dynamic method with . + /// + [MethodImpl(MethodImplOptions.NoInlining)] + private static NetDynamicMethod CreateDynamicMethod(string methodName, Type returnType, Type[] argumentTypes, MemberInfo member, bool skipVisibility) + { + NetDynamicMethod dmGetter = null; + methodName = "_dynamic_" + member.DeclaringType.Name + "." + methodName; + try + { + new PermissionSet(PermissionState.Unrestricted).Demand(); + dmGetter = CreateDynamicMethodInternal(methodName, returnType, argumentTypes, member, skipVisibility); + } + catch(SecurityException) + { + dmGetter = CreateDynamicMethodInternal(methodName, returnType, argumentTypes, MethodBase.GetCurrentMethod(), false); + } + return dmGetter; + } + + private static NetDynamicMethod CreateDynamicMethodInternal(string methodName, Type returnType, Type[] argumentTypes, MemberInfo member, bool skipVisibility) + { + NetDynamicMethod dm; + dm = new NetDynamicMethod(methodName, returnType, argumentTypes, member.Module, skipVisibility); +// if (member is FieldInfo) +// { +// // workaround for DynamicMethod bug not invoking type initializer before accessing static field +// // it seems all works correct if the DM is created with limited accessibility +// bool isStatic = (((FieldInfo) member).IsStatic); +// if (isStatic) +// { +// new ReflectionPermission(ReflectionPermissionFlag.MemberAccess).PermitOnly(); +// } +// dm = new NetDynamicMethod(methodName, returnType, argumentTypes, member.DeclaringType, true); +// if (isStatic) +// { +// CodeAccessPermission.RevertPermitOnly(); +// } +// } +// else +// { +// dm = new NetDynamicMethod(methodName, returnType, argumentTypes, member.DeclaringType, true); +// } + return dm; + } + + private static bool IsPublic(MemberInfo member) + { + if (member == null) return true; + + switch(member.MemberType) + { + case MemberTypes.Event: + { + bool isPublic = ((EventInfo) member).GetAddMethod() != null; + return isPublic && IsPublic(member.DeclaringType); + } + case MemberTypes.Field: + { + bool isPublic = ((FieldInfo)member).IsPublic; + return isPublic && IsPublic(member.DeclaringType); + } + case MemberTypes.Property: + { + throw new NotSupportedException(); + } + case MemberTypes.Constructor: + case MemberTypes.Method: + { + bool isPublic = ((MethodBase)member).IsPublic; + return isPublic && IsPublic(member.DeclaringType); + } + case MemberTypes.NestedType: + { + bool isPublic = ((Type)member).IsPublic; + return isPublic && IsPublic(member.DeclaringType); + } + case MemberTypes.TypeInfo: + { + bool isPublic = ((Type)member).IsPublic; + return isPublic; + } + default: + throw new NotSupportedException(); + } + } #endif #region Shared Code Generation - private static void EmitFieldGetter( ILGenerator il, FieldInfo fieldInfo, bool isInstanceMethod ) + private static void EmitFieldGetter(ILGenerator il, FieldInfo fieldInfo, bool isInstanceMethod) { if (fieldInfo.IsLiteral) { - object value = fieldInfo.GetValue( null ); - EmitConstant( il, value ); + object value = fieldInfo.GetValue(null); + EmitConstant(il, value); } else if (fieldInfo.IsStatic) { - il.Emit( OpCodes.Ldsfld, fieldInfo ); +// object v = fieldInfo.GetValue(null); // ensure type is initialized... + il.Emit(OpCodes.Ldsfld, fieldInfo); } else { - EmitTarget( il, fieldInfo.DeclaringType, isInstanceMethod ); - il.Emit( OpCodes.Ldfld, fieldInfo ); + EmitTarget(il, fieldInfo.DeclaringType, isInstanceMethod); + il.Emit(OpCodes.Ldfld, fieldInfo); } if (fieldInfo.FieldType.IsValueType) { - il.Emit( OpCodes.Box, fieldInfo.FieldType ); + il.Emit(OpCodes.Box, fieldInfo.FieldType); } - il.Emit( OpCodes.Ret ); + il.Emit(OpCodes.Ret); } - internal static void EmitFieldSetter( ILGenerator il, FieldInfo fieldInfo, bool isInstanceMethod ) + internal static void EmitFieldSetter(ILGenerator il, FieldInfo fieldInfo, bool isInstanceMethod) { if (!fieldInfo.IsLiteral && !fieldInfo.IsInitOnly @@ -417,51 +524,51 @@ namespace Spring.Reflection.Dynamic { if (!fieldInfo.IsStatic) { - EmitTarget( il, fieldInfo.DeclaringType, isInstanceMethod ); + EmitTarget(il, fieldInfo.DeclaringType, isInstanceMethod); } - il.Emit( OpCodes.Ldarg_1 ); + il.Emit(OpCodes.Ldarg_1); if (fieldInfo.FieldType.IsValueType) { - EmitUnbox( il, fieldInfo.FieldType ); + EmitUnbox(il, fieldInfo.FieldType); } else { - il.Emit( OpCodes.Castclass, fieldInfo.FieldType ); + il.Emit(OpCodes.Castclass, fieldInfo.FieldType); } if (fieldInfo.IsStatic) { - il.Emit( OpCodes.Stsfld, fieldInfo ); + il.Emit(OpCodes.Stsfld, fieldInfo); } else { - il.Emit( OpCodes.Stfld, fieldInfo ); + il.Emit(OpCodes.Stfld, fieldInfo); } - il.Emit( OpCodes.Ret ); + il.Emit(OpCodes.Ret); } else { - EmitThrowInvalidOperationException( il, string.Format( "Cannot write to read-only field '{0}.{1}'", fieldInfo.DeclaringType.FullName, fieldInfo.Name ) ); + EmitThrowInvalidOperationException(il, string.Format("Cannot write to read-only field '{0}.{1}'", fieldInfo.DeclaringType.FullName, fieldInfo.Name)); } } - internal static void EmitPropertyGetter( ILGenerator il, PropertyInfo propertyInfo, bool isInstanceMethod ) + internal static void EmitPropertyGetter(ILGenerator il, PropertyInfo propertyInfo, bool isInstanceMethod) { if (propertyInfo.CanRead) { - MethodInfo getMethod = propertyInfo.GetGetMethod( true ); - EmitInvokeMethod( il, getMethod, isInstanceMethod ); + MethodInfo getMethod = propertyInfo.GetGetMethod(true); + EmitInvokeMethod(il, getMethod, isInstanceMethod); } else { - EmitThrowInvalidOperationException( il, string.Format( "Cannot read from write-only property '{0}.{1}'", propertyInfo.DeclaringType.FullName, propertyInfo.Name ) ); + EmitThrowInvalidOperationException(il, string.Format("Cannot read from write-only property '{0}.{1}'", propertyInfo.DeclaringType.FullName, propertyInfo.Name)); } } - internal static void EmitPropertySetter( ILGenerator il, PropertyInfo propertyInfo, bool isInstanceMethod ) + internal static void EmitPropertySetter(ILGenerator il, PropertyInfo propertyInfo, bool isInstanceMethod) { - MethodInfo method = propertyInfo.GetSetMethod( true ); + MethodInfo method = propertyInfo.GetSetMethod(true); if (propertyInfo.CanWrite && !(propertyInfo.DeclaringType.IsValueType && !method.IsStatic)) @@ -475,184 +582,184 @@ namespace Spring.Reflection.Dynamic ParameterInfo[] args = propertyInfo.GetIndexParameters(); // get indexParameters here! for (int i = 0; i < args.Length; i++) { - SetupOutputArgument( il, paramsArrayPosition, args[i], outArgs ); + SetupOutputArgument(il, paramsArrayPosition, args[i], outArgs); } // load target if (!method.IsStatic) { - EmitTarget( il, method.DeclaringType, isInstanceMethod ); + EmitTarget(il, method.DeclaringType, isInstanceMethod); } // load indexer arguments for (int i = 0; i < args.Length; i++) { - SetupMethodArgument( il, paramsArrayPosition, args[i], outArgs ); + SetupMethodArgument(il, paramsArrayPosition, args[i], outArgs); } // load value - il.Emit( OpCodes.Ldarg_1 ); + il.Emit(OpCodes.Ldarg_1); if (propertyInfo.PropertyType.IsValueType) { - EmitUnbox( il, propertyInfo.PropertyType ); + EmitUnbox(il, propertyInfo.PropertyType); } else { - il.Emit( OpCodes.Castclass, propertyInfo.PropertyType ); + il.Emit(OpCodes.Castclass, propertyInfo.PropertyType); } // call setter - EmitCall( il, method ); + EmitCall(il, method); for (int i = 0; i < args.Length; i++) { - ProcessOutputArgument( il, paramsArrayPosition, args[i], outArgs ); + ProcessOutputArgument(il, paramsArrayPosition, args[i], outArgs); } - il.Emit( OpCodes.Ret ); + il.Emit(OpCodes.Ret); } else { - EmitThrowInvalidOperationException( il, string.Format( "Cannot write to read-only property '{0}.{1}'", propertyInfo.DeclaringType.FullName, propertyInfo.Name ) ); + EmitThrowInvalidOperationException(il, string.Format("Cannot write to read-only property '{0}.{1}'", propertyInfo.DeclaringType.FullName, propertyInfo.Name)); } } /// /// Delegates a Method(object target, params object[] args) call to the actual underlying method. /// - internal static void EmitInvokeMethod( ILGenerator il, MethodInfo method, bool isInstanceMethod ) + internal static void EmitInvokeMethod(ILGenerator il, MethodInfo method, bool isInstanceMethod) { int paramsArrayPosition = (isInstanceMethod) ? 2 : 1; ParameterInfo[] args = method.GetParameters(); IDictionary outArgs = new Hashtable(); for (int i = 0; i < args.Length; i++) { - SetupOutputArgument( il, paramsArrayPosition, args[i], outArgs ); + SetupOutputArgument(il, paramsArrayPosition, args[i], outArgs); } if (!method.IsStatic) { - EmitTarget( il, method.DeclaringType, isInstanceMethod ); + EmitTarget(il, method.DeclaringType, isInstanceMethod); } for (int i = 0; i < args.Length; i++) { - SetupMethodArgument( il, paramsArrayPosition, args[i], outArgs ); + SetupMethodArgument(il, paramsArrayPosition, args[i], outArgs); } - EmitCall( il, method ); + EmitCall(il, method); for (int i = 0; i < args.Length; i++) { - ProcessOutputArgument( il, paramsArrayPosition, args[i], outArgs ); + ProcessOutputArgument(il, paramsArrayPosition, args[i], outArgs); } - EmitMethodReturn( il, method.ReturnType ); + EmitMethodReturn(il, method.ReturnType); } internal static void EmitInvokeConstructor(ILGenerator il, ConstructorInfo constructor, bool isInstanceMethod) { int paramsArrayPosition = (isInstanceMethod) ? 1 : 0; - ParameterInfo[] args = constructor.GetParameters(); - + ParameterInfo[] args = constructor.GetParameters(); + IDictionary outArgs = new Hashtable(); for (int i = 0; i < args.Length; i++) { - SetupOutputArgument( il, paramsArrayPosition, args[i], outArgs ); + SetupOutputArgument(il, paramsArrayPosition, args[i], outArgs); } - - for (int i = 0; i < args.Length; i++) - { - SetupMethodArgument(il, paramsArrayPosition, args[i], null); - } - - il.Emit(OpCodes.Newobj, constructor); - + for (int i = 0; i < args.Length; i++) { - ProcessOutputArgument( il, paramsArrayPosition, args[i], outArgs ); + SetupMethodArgument(il, paramsArrayPosition, args[i], null); } - - EmitMethodReturn(il, constructor.DeclaringType); - } - + + il.Emit(OpCodes.Newobj, constructor); + + for (int i = 0; i < args.Length; i++) + { + ProcessOutputArgument(il, paramsArrayPosition, args[i], outArgs); + } + + EmitMethodReturn(il, constructor.DeclaringType); + } + #endregion private static OpCode[] LdArgOpCodes = { OpCodes.Ldarg_0, OpCodes.Ldarg_1, OpCodes.Ldarg_2 }; - private static void SetupOutputArgument( ILGenerator il, int paramsArrayPosition, ParameterInfo argInfo, IDictionary outArgs ) + private static void SetupOutputArgument(ILGenerator il, int paramsArrayPosition, ParameterInfo argInfo, IDictionary outArgs) { - if (!IsOutputOrRefArgument( argInfo )) + if (!IsOutputOrRefArgument(argInfo)) return; Type argType = argInfo.ParameterType.GetElementType(); - LocalBuilder lb = il.DeclareLocal( argType ); + LocalBuilder lb = il.DeclareLocal(argType); if (!argInfo.IsOut) { - PushParamsArgumentValue( il, paramsArrayPosition, argType, argInfo.Position ); - il.Emit( OpCodes.Stloc, lb ); + PushParamsArgumentValue(il, paramsArrayPosition, argType, argInfo.Position); + il.Emit(OpCodes.Stloc, lb); } outArgs[argInfo.Position] = lb; } - private static bool IsOutputOrRefArgument( ParameterInfo argInfo ) + private static bool IsOutputOrRefArgument(ParameterInfo argInfo) { - return argInfo.IsOut || argInfo.ParameterType.Name.EndsWith( "&" ); + return argInfo.IsOut || argInfo.ParameterType.Name.EndsWith("&"); } - private static void ProcessOutputArgument( ILGenerator il, int paramsArrayPosition, ParameterInfo argInfo, IDictionary outArgs ) + private static void ProcessOutputArgument(ILGenerator il, int paramsArrayPosition, ParameterInfo argInfo, IDictionary outArgs) { - if (!IsOutputOrRefArgument( argInfo )) + if (!IsOutputOrRefArgument(argInfo)) return; Type argType = argInfo.ParameterType.GetElementType(); - il.Emit( LdArgOpCodes[paramsArrayPosition] ); - il.Emit( OpCodes.Ldc_I4, argInfo.Position ); - il.Emit( OpCodes.Ldloc, (LocalBuilder)outArgs[argInfo.Position] ); + il.Emit(LdArgOpCodes[paramsArrayPosition]); + il.Emit(OpCodes.Ldc_I4, argInfo.Position); + il.Emit(OpCodes.Ldloc, (LocalBuilder)outArgs[argInfo.Position]); if (argType.IsValueType) { - il.Emit( OpCodes.Box, argType ); + il.Emit(OpCodes.Box, argType); } - il.Emit( OpCodes.Stelem_Ref ); + il.Emit(OpCodes.Stelem_Ref); } - private static void SetupMethodArgument( ILGenerator il, int paramsArrayPosition, ParameterInfo argInfo, IDictionary outArgs ) + private static void SetupMethodArgument(ILGenerator il, int paramsArrayPosition, ParameterInfo argInfo, IDictionary outArgs) { - if ( IsOutputOrRefArgument( argInfo )) + if (IsOutputOrRefArgument(argInfo)) { - il.Emit( OpCodes.Ldloca_S, (LocalBuilder)outArgs[argInfo.Position] ); + il.Emit(OpCodes.Ldloca_S, (LocalBuilder)outArgs[argInfo.Position]); } else { - PushParamsArgumentValue( il, paramsArrayPosition, argInfo.ParameterType, argInfo.Position ); + PushParamsArgumentValue(il, paramsArrayPosition, argInfo.ParameterType, argInfo.Position); } } - private static void PushParamsArgumentValue( ILGenerator il, int paramsArrayPosition, Type argumentType, int argumentPosition ) + private static void PushParamsArgumentValue(ILGenerator il, int paramsArrayPosition, Type argumentType, int argumentPosition) { - il.Emit( LdArgOpCodes[paramsArrayPosition] ); - il.Emit( OpCodes.Ldc_I4, argumentPosition ); - il.Emit( OpCodes.Ldelem_Ref ); + il.Emit(LdArgOpCodes[paramsArrayPosition]); + il.Emit(OpCodes.Ldc_I4, argumentPosition); + il.Emit(OpCodes.Ldelem_Ref); if (argumentType.IsValueType) { // call ConvertArgumentIfNecessary() to convert e.g. int32 to double if necessary - il.Emit( OpCodes.Ldtoken, argumentType ); - EmitCall( il, FnGetTypeFromHandle ); - il.Emit( OpCodes.Ldc_I4, argumentPosition ); - EmitCall( il, FnConvertArgumentIfNecessary ); - EmitUnbox( il, argumentType ); + il.Emit(OpCodes.Ldtoken, argumentType); + EmitCall(il, FnGetTypeFromHandle); + il.Emit(OpCodes.Ldc_I4, argumentPosition); + EmitCall(il, FnConvertArgumentIfNecessary); + EmitUnbox(il, argumentType); } else { - il.Emit( OpCodes.Castclass, argumentType ); + il.Emit(OpCodes.Castclass, argumentType); } } - private static void EmitUnbox( ILGenerator il, Type argumentType ) + private static void EmitUnbox(ILGenerator il, Type argumentType) { #if NET_2_0 - il.Emit( OpCodes.Unbox_Any, argumentType ); + il.Emit(OpCodes.Unbox_Any, argumentType); #else il.Emit(OpCodes.Unbox, argumentType); il.Emit(OpCodes.Ldobj, argumentType); @@ -664,23 +771,23 @@ namespace Spring.Reflection.Dynamic /// /// IL generator to use. /// Type of the return value. - private static void EmitMethodReturn( ILGenerator il, Type returnValueType ) + private static void EmitMethodReturn(ILGenerator il, Type returnValueType) { - if (returnValueType == typeof( void )) + if (returnValueType == typeof(void)) { - il.Emit( OpCodes.Ldnull ); + il.Emit(OpCodes.Ldnull); } else if (returnValueType.IsValueType) { - il.Emit( OpCodes.Box, returnValueType ); + il.Emit(OpCodes.Box, returnValueType); } - il.Emit( OpCodes.Ret ); + il.Emit(OpCodes.Ret); } - private delegate Type GetTypeFromHandleDelegate( RuntimeTypeHandle handle ); - private static readonly MethodInfo FnGetTypeFromHandle = new GetTypeFromHandleDelegate( Type.GetTypeFromHandle ).Method; - private delegate object ChangeTypeDelegate( object value, Type targetType, int argIndex ); - private static readonly MethodInfo FnConvertArgumentIfNecessary = new ChangeTypeDelegate( ConvertValueTypeArgumentIfNecessary ).Method; + private delegate Type GetTypeFromHandleDelegate(RuntimeTypeHandle handle); + private static readonly MethodInfo FnGetTypeFromHandle = new GetTypeFromHandleDelegate(Type.GetTypeFromHandle).Method; + private delegate object ChangeTypeDelegate(object value, Type targetType, int argIndex); + private static readonly MethodInfo FnConvertArgumentIfNecessary = new ChangeTypeDelegate(ConvertValueTypeArgumentIfNecessary).Method; /// /// Converts to an instance of if necessary to @@ -696,7 +803,7 @@ namespace Spring.Reflection.Dynamic /// Note: is expected to be a value type! /// /// - public static object ConvertValueTypeArgumentIfNecessary( object value, Type targetType, int argIndex ) + public static object ConvertValueTypeArgumentIfNecessary(object value, Type targetType, int argIndex) { if (value == null) { @@ -704,12 +811,12 @@ namespace Spring.Reflection.Dynamic { return null; } - throw new InvalidCastException( string.Format( "Cannot convert NULL at position {0} to argument type {1}", argIndex, targetType.FullName ) ); + throw new InvalidCastException(string.Format("Cannot convert NULL at position {0} to argument type {1}", argIndex, targetType.FullName)); } Type valueType = value.GetType(); #if NET_2_0 - if (ReflectionUtils.IsNullableType( targetType )) + if (ReflectionUtils.IsNullableType(targetType)) { targetType = Nullable.GetUnderlyingType(targetType); } @@ -723,47 +830,47 @@ namespace Spring.Reflection.Dynamic if (!valueType.IsValueType) { // we're facing a reftype/valuetype mix that never can convert - throw new InvalidCastException( string.Format( "Cannot convert value '{0}' of type {1} at position {2} to argument type {3}", value, valueType.FullName, argIndex, targetType.FullName ) ); + throw new InvalidCastException(string.Format("Cannot convert value '{0}' of type {1} at position {2} to argument type {3}", value, valueType.FullName, argIndex, targetType.FullName)); } // we're dealing only with ValueType's now - try to convert them try { // TODO: allow widening conversions only - return Convert.ChangeType( value, targetType ); + return Convert.ChangeType(value, targetType); } catch (Exception ex) { - throw new InvalidCastException( string.Format( "Cannot convert value '{0}' of type {1} at position {2} to argument type {3}", value, valueType.FullName, argIndex, targetType.FullName ), ex ); + throw new InvalidCastException(string.Format("Cannot convert value '{0}' of type {1} at position {2} to argument type {3}", value, valueType.FullName, argIndex, targetType.FullName), ex); } } - private static void EmitTarget( ILGenerator il, Type targetType, bool isInstanceMethod ) + private static void EmitTarget(ILGenerator il, Type targetType, bool isInstanceMethod) { - il.Emit( (isInstanceMethod) ? OpCodes.Ldarg_1 : OpCodes.Ldarg_0 ); + il.Emit((isInstanceMethod) ? OpCodes.Ldarg_1 : OpCodes.Ldarg_0); if (targetType.IsValueType) { - LocalBuilder local = il.DeclareLocal( targetType ); - EmitUnbox( il, targetType ); - il.Emit( OpCodes.Stloc_0 ); - il.Emit( OpCodes.Ldloca_S, 0 ); + LocalBuilder local = il.DeclareLocal(targetType); + EmitUnbox(il, targetType); + il.Emit(OpCodes.Stloc_0); + il.Emit(OpCodes.Ldloca_S, 0); } else { - il.Emit( OpCodes.Castclass, targetType ); + il.Emit(OpCodes.Castclass, targetType); } } - private static void EmitCall( ILGenerator il, MethodInfo method ) + private static void EmitCall(ILGenerator il, MethodInfo method) { - il.EmitCall( (method.IsVirtual) ? OpCodes.Callvirt : OpCodes.Call, method, null ); + il.EmitCall((method.IsVirtual) ? OpCodes.Callvirt : OpCodes.Call, method, null); } - private static void EmitConstant( ILGenerator il, object value ) + private static void EmitConstant(ILGenerator il, object value) { if (value is String) { - il.Emit( OpCodes.Ldstr, (string)value ); + il.Emit(OpCodes.Ldstr, (string)value); return; } @@ -771,78 +878,78 @@ namespace Spring.Reflection.Dynamic { if ((bool)value) { - il.Emit( OpCodes.Ldc_I4_1 ); + il.Emit(OpCodes.Ldc_I4_1); } else { - il.Emit( OpCodes.Ldc_I4_0 ); + il.Emit(OpCodes.Ldc_I4_0); } return; } if (value is Char) { - il.Emit( OpCodes.Ldc_I4, (Char)value ); - il.Emit( OpCodes.Conv_I2 ); + il.Emit(OpCodes.Ldc_I4, (Char)value); + il.Emit(OpCodes.Conv_I2); return; } if (value is byte) { - il.Emit( OpCodes.Ldc_I4, (byte)value ); - il.Emit( OpCodes.Conv_I1 ); + il.Emit(OpCodes.Ldc_I4, (byte)value); + il.Emit(OpCodes.Conv_I1); } else if (value is Int16) { - il.Emit( OpCodes.Ldc_I4, (Int16)value ); - il.Emit( OpCodes.Conv_I2 ); + il.Emit(OpCodes.Ldc_I4, (Int16)value); + il.Emit(OpCodes.Conv_I2); } else if (value is Int32) { - il.Emit( OpCodes.Ldc_I4, (Int32)value ); + il.Emit(OpCodes.Ldc_I4, (Int32)value); } else if (value is Int64) { - il.Emit( OpCodes.Ldc_I8, (Int64)value ); + il.Emit(OpCodes.Ldc_I8, (Int64)value); } else if (value is UInt16) { - il.Emit( OpCodes.Ldc_I4, (UInt16)value ); - il.Emit( OpCodes.Conv_U2 ); + il.Emit(OpCodes.Ldc_I4, (UInt16)value); + il.Emit(OpCodes.Conv_U2); } else if (value is UInt32) { - il.Emit( OpCodes.Ldc_I4, (UInt32)value ); - il.Emit( OpCodes.Conv_U4 ); + il.Emit(OpCodes.Ldc_I4, (UInt32)value); + il.Emit(OpCodes.Conv_U4); } else if (value is UInt64) { - il.Emit( OpCodes.Ldc_I8, (UInt64)value ); - il.Emit( OpCodes.Conv_U8 ); + il.Emit(OpCodes.Ldc_I8, (UInt64)value); + il.Emit(OpCodes.Conv_U8); } else if (value is Single) { - il.Emit( OpCodes.Ldc_R4, (Single)value ); + il.Emit(OpCodes.Ldc_R4, (Single)value); } else if (value is Double) { - il.Emit( OpCodes.Ldc_R8, (Double)value ); + il.Emit(OpCodes.Ldc_R8, (Double)value); } } private static readonly ConstructorInfo NewInvalidOperationException = - typeof( InvalidOperationException ).GetConstructor( new Type[] { typeof( string ) } ); + typeof(InvalidOperationException).GetConstructor(new Type[] { typeof(string) }); /// /// Generates code that throws . /// /// IL generator to use. /// Error message to use. - private static void EmitThrowInvalidOperationException( ILGenerator il, string message ) + private static void EmitThrowInvalidOperationException(ILGenerator il, string message) { - il.Emit( OpCodes.Ldstr, message ); - il.Emit( OpCodes.Newobj, NewInvalidOperationException ); - il.Emit( OpCodes.Throw ); + il.Emit(OpCodes.Ldstr, message); + il.Emit(OpCodes.Newobj, NewInvalidOperationException); + il.Emit(OpCodes.Throw); } } } \ No newline at end of file diff --git a/src/Spring/Spring.Core/Spring.Core.2008.csproj b/src/Spring/Spring.Core/Spring.Core.2008.csproj index 97de62a9..9bd72de8 100644 --- a/src/Spring/Spring.Core/Spring.Core.2008.csproj +++ b/src/Spring/Spring.Core/Spring.Core.2008.csproj @@ -11,8 +11,6 @@ Spring.Core - - JScript Grid IE50 @@ -38,6 +36,8 @@ true false true + true + ..\..\..\Spring.Net.snk ..\..\..\build\VS.Net.2008\Spring.Core\Debug\ @@ -1013,6 +1013,7 @@ + diff --git a/src/Spring/Spring.Core/Util/ObjectUtils.cs b/src/Spring/Spring.Core/Util/ObjectUtils.cs index ea048574..57168af7 100644 --- a/src/Spring/Spring.Core/Util/ObjectUtils.cs +++ b/src/Spring/Spring.Core/Util/ObjectUtils.cs @@ -247,8 +247,7 @@ namespace Spring.Util #endif try { - // replaced with SafeConstructor() to avoid nasty "TargetInvocationException"s - //return constructor.Invoke(arguments); + // replaced with SafeConstructor() to avoid nasty "TargetInvocationException"s in NET >= 2.0 return (new SafeConstructor(constructor)).Invoke(arguments); } catch (Exception ex) diff --git a/src/Spring/Spring.Core/Util/ReflectionUtils.cs b/src/Spring/Spring.Core/Util/ReflectionUtils.cs index b1c97647..46c791ca 100644 --- a/src/Spring/Spring.Core/Util/ReflectionUtils.cs +++ b/src/Spring/Spring.Core/Util/ReflectionUtils.cs @@ -1,5 +1,5 @@ -#region License - +#region License + /* * Copyright © 2002-2005 the original author or authors. * @@ -14,132 +14,139 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - */ - -#endregion - -#region Imports - -using System; -using System.Collections; -#if NET_2_0 -using System.Collections.Generic; -using System.Collections.ObjectModel; -#endif -using System.Globalization; -using System.Reflection; -using System.Reflection.Emit; -using System.Text; -using System.Runtime.CompilerServices; - -#endregion - -namespace Spring.Util -{ - /// - /// Various reflection related methods that are missing from the standard library. - /// - /// Rod Johnson - /// Juergen Hoeller - /// Aleksandar Seovic (.NET) - /// Stan Dvoychenko (.NET) - /// Bruno Baia (.NET) - public sealed class ReflectionUtils - { - /// - /// Convenience value that will - /// match all private and public, static and instance members on a class - /// in a case inSenSItivE fashion. - /// - public const BindingFlags AllMembersCaseInsensitiveFlags = BindingFlags.Public | - BindingFlags.NonPublic | BindingFlags.Instance - | BindingFlags.Static + */ + +#endregion + +#region Imports + +using System; +using System.Collections; +#if NET_2_0 +using System.Collections.ObjectModel; +#endif +using System.Globalization; +using System.Reflection; +using System.Reflection.Emit; +using System.Security; +using System.Security.Permissions; +using System.Text; +using System.Runtime.CompilerServices; + +#endregion + +namespace Spring.Util +{ + /// + /// Various reflection related methods that are missing from the standard library. + /// + /// Rod Johnson + /// Juergen Hoeller + /// Aleksandar Seovic (.NET) + /// Stan Dvoychenko (.NET) + /// Bruno Baia (.NET) + public sealed class ReflectionUtils + { + /// + /// Convenience value that will + /// match all private and public, static and instance members on a class + /// in a case inSenSItivE fashion. + /// + public const BindingFlags AllMembersCaseInsensitiveFlags = BindingFlags.Public | + BindingFlags.NonPublic | BindingFlags.Instance + | BindingFlags.Static | BindingFlags.IgnoreCase; + /// + /// Avoid BeforeFieldInit problem + /// + static ReflectionUtils() + {} + /// /// Checks, if the specified type is a nullable /// - public static bool IsNullableType( Type type ) + public static bool IsNullableType(Type type) { #if NET_2_0 - return (type.IsGenericType && type.GetGenericTypeDefinition()==typeof(Nullable<>)); + return (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)); #else return false; #endif - } - - /// - /// Returns signature for the specified , method name and argument - /// s. - /// - /// The the method is in. - /// The method name. - /// - /// The argument s. - /// - /// The method signature. - public static string GetSignature( - Type type, string method, Type[] argumentTypes) - { - StringBuilder sb = new StringBuilder(); - sb.Append(type.FullName).Append("::").Append(method).Append("("); - string separator = ""; - for (int i = 0; i < argumentTypes.Length; i++) - { - sb.Append(separator).Append(argumentTypes[i].FullName); - separator = ","; - } - sb.Append(")"); - return sb.ToString(); - } - - - /// - /// Returns method for the specified , method - /// name and argument - /// s. - /// + } + + /// + /// Returns signature for the specified , method name and argument + /// s. + /// + /// The the method is in. + /// The method name. + /// + /// The argument s. + /// + /// The method signature. + public static string GetSignature( + Type type, string method, Type[] argumentTypes) + { + StringBuilder sb = new StringBuilder(); + sb.Append(type.FullName).Append("::").Append(method).Append("("); + string separator = ""; + for (int i = 0; i < argumentTypes.Length; i++) + { + sb.Append(separator).Append(argumentTypes[i].FullName); + separator = ","; + } + sb.Append(")"); + return sb.ToString(); + } + + + /// + /// Returns method for the specified , method + /// name and argument + /// s. + /// /// /// Searches with BindingFlags /// When dealing with interface methods, you probable want to 'normalize' method references by calling /// . /// - /// - /// - /// The target to find the method on. - /// - /// The method to find. - /// - /// The argument s. May be - /// if the method has no arguments. - /// + /// + /// + /// The target to find the method on. + /// + /// The method to find. + /// + /// The argument s. May be + /// if the method has no arguments. + /// /// The target method. - /// - public static MethodInfo GetMethod( - Type targetType, string method, Type[] argumentTypes) - { - AssertUtils.ArgumentNotNull(targetType, "Type must not be null"); - // try method exactly as specified first... - MethodInfo retMethod = targetType.GetMethod( - method, - ReflectionUtils.AllMembersCaseInsensitiveFlags, - null, - argumentTypes == null ? Type.EmptyTypes : argumentTypes, - null); - - if (retMethod == null) - { - // try explicit interface implementation... - int idx = method.LastIndexOf('.'); - if (idx > -1) - { - method = method.Substring(idx + 1); - retMethod = ReflectionUtils.GetMethod(targetType, method, argumentTypes); - } - } - return retMethod; - } - + /// + public static MethodInfo GetMethod( + Type targetType, string method, Type[] argumentTypes) + { + AssertUtils.ArgumentNotNull(targetType, "Type must not be null"); + // try method exactly as specified first... + MethodInfo retMethod = targetType.GetMethod( + method, + ReflectionUtils.AllMembersCaseInsensitiveFlags, + null, + argumentTypes == null ? Type.EmptyTypes : argumentTypes, + null); + + if (retMethod == null) + { + // try explicit interface implementation... + int idx = method.LastIndexOf('.'); + if (idx > -1) + { + method = method.Substring(idx + 1); + retMethod = ReflectionUtils.GetMethod(targetType, method, argumentTypes); + } + } + return retMethod; + } + /// /// Resolves a given to the representing the actual implementation. /// @@ -148,8 +155,8 @@ namespace Spring.Util /// /// a /// the type to lookup - /// the representing the actual implementation method of the specified - public static MethodInfo MapInterfaceMethodToImplementationIfNecessary( MethodInfo methodInfo, System.Type implementingType ) + /// the representing the actual implementation method of the specified + public static MethodInfo MapInterfaceMethodToImplementationIfNecessary(MethodInfo methodInfo, System.Type implementingType) { AssertUtils.ArgumentNotNull(methodInfo, "methodInfo"); AssertUtils.ArgumentNotNull(implementingType, "implementingType"); @@ -159,817 +166,817 @@ namespace Spring.Util if (methodInfo.DeclaringType.IsInterface) { - InterfaceMapping interfaceMapping = implementingType.GetInterfaceMap( methodInfo.DeclaringType ); - int methodIndex = Array.IndexOf( interfaceMapping.InterfaceMethods, methodInfo ); + InterfaceMapping interfaceMapping = implementingType.GetInterfaceMap(methodInfo.DeclaringType); + int methodIndex = Array.IndexOf(interfaceMapping.InterfaceMethods, methodInfo); concreteMethodInfo = interfaceMapping.TargetMethods[methodIndex]; } return concreteMethodInfo; } - - /// - /// Returns an array of parameter s for the specified method - /// or constructor. - /// - /// The method (or constructor). - /// An array containing the parameter s. - /// - /// If is . - /// - public static Type[] GetParameterTypes(MethodBase method) - { - AssertUtils.ArgumentNotNull(method, "method"); - return GetParameterTypes(method.GetParameters()); - } - - /// - /// Returns an array of parameter s for the - /// specified parameter info array. - /// - /// The parameter info array. - /// An array containing parameter s. - /// - /// If is or any of the - /// elements is . - /// - public static Type[] GetParameterTypes(ParameterInfo[] args) - { - AssertUtils.ArgumentNotNull(args, "args"); - Type[] types = new Type[args.Length]; - for (int i = 0; i < args.Length; i++) - { - types[i] = args[i].ParameterType; - } - return types; - } - -#if NET_2_0 - /// - /// Returns an array of s that represent - /// the names of the generic type parameter. - /// - /// The method. - /// An array containing the parameter names. - /// - /// If is . - /// - public static string[] GetGenericParameterNames(MethodInfo method) - { - AssertUtils.ArgumentNotNull(method, "method"); - return GetGenericParameterNames(method.GetGenericArguments()); - } - - /// - /// Returns an array of s that represent - /// the names of the generic type parameter. - /// - /// The parameter info array. - /// An array containing parameter names. - /// - /// If is or any of the - /// elements is . - /// - public static string[] GetGenericParameterNames(Type[] args) - { - AssertUtils.ArgumentNotNull(args, "args"); - string[] names = new string[args.Length]; - for (int i = 0; i < args.Length; i++) - { - names[i] = args[i].Name; - } - return names; - } -#endif - - /// - /// From a given list of methods, selects the method having an exact match on the given ' types. - /// - /// the list of methods to choose from - /// the arguments to the method - /// the method matching exactly the passed ' types - /// - /// If more than 1 matching methods are found in the list. - /// - public static MethodInfo GetMethodByArgumentValues(MethodInfo[] methods, object[] argValues) - { - return (MethodInfo)GetMethodBaseByArgumentValues("method", methods, argValues); - } - - /// - /// From a given list of methods, selects the method having an exact match on the given ' types. - /// - /// the type of method (used for exception reporting only) - /// the list of methods to choose from - /// the arguments to the method - /// the method matching exactly the passed ' types - /// - /// If more than 1 matching methods are found in the list. - /// - private static MethodBase GetMethodBaseByArgumentValues(string methodTypeName, MethodBase[] methods, - object[] argValues) - { - MethodBase match = null; - int matchCount = 0; - - foreach (MethodBase m in methods) - { - ParameterInfo[] parameters = m.GetParameters(); - bool isMatch = true; - bool isExactMatch = true; - object[] paramValues = (argValues==null)?new object[0] : argValues; - - try - { - if (parameters.Length > 0) - { - ParameterInfo lastParameter = parameters[parameters.Length - 1]; - if (lastParameter.GetCustomAttributes(typeof(ParamArrayAttribute), false).Length > 0) - { - paramValues = - PackageParamArray(argValues, parameters.Length, - lastParameter.ParameterType.GetElementType()); - } - } - - if (parameters.Length != paramValues.Length) + + /// + /// Returns an array of parameter s for the specified method + /// or constructor. + /// + /// The method (or constructor). + /// An array containing the parameter s. + /// + /// If is . + /// + public static Type[] GetParameterTypes(MethodBase method) + { + AssertUtils.ArgumentNotNull(method, "method"); + return GetParameterTypes(method.GetParameters()); + } + + /// + /// Returns an array of parameter s for the + /// specified parameter info array. + /// + /// The parameter info array. + /// An array containing parameter s. + /// + /// If is or any of the + /// elements is . + /// + public static Type[] GetParameterTypes(ParameterInfo[] args) + { + AssertUtils.ArgumentNotNull(args, "args"); + Type[] types = new Type[args.Length]; + for (int i = 0; i < args.Length; i++) + { + types[i] = args[i].ParameterType; + } + return types; + } + +#if NET_2_0 + /// + /// Returns an array of s that represent + /// the names of the generic type parameter. + /// + /// The method. + /// An array containing the parameter names. + /// + /// If is . + /// + public static string[] GetGenericParameterNames(MethodInfo method) + { + AssertUtils.ArgumentNotNull(method, "method"); + return GetGenericParameterNames(method.GetGenericArguments()); + } + + /// + /// Returns an array of s that represent + /// the names of the generic type parameter. + /// + /// The parameter info array. + /// An array containing parameter names. + /// + /// If is or any of the + /// elements is . + /// + public static string[] GetGenericParameterNames(Type[] args) + { + AssertUtils.ArgumentNotNull(args, "args"); + string[] names = new string[args.Length]; + for (int i = 0; i < args.Length; i++) + { + names[i] = args[i].Name; + } + return names; + } +#endif + + /// + /// From a given list of methods, selects the method having an exact match on the given ' types. + /// + /// the list of methods to choose from + /// the arguments to the method + /// the method matching exactly the passed ' types + /// + /// If more than 1 matching methods are found in the list. + /// + public static MethodInfo GetMethodByArgumentValues(MethodInfo[] methods, object[] argValues) + { + return (MethodInfo)GetMethodBaseByArgumentValues("method", methods, argValues); + } + + /// + /// From a given list of methods, selects the method having an exact match on the given ' types. + /// + /// the type of method (used for exception reporting only) + /// the list of methods to choose from + /// the arguments to the method + /// the method matching exactly the passed ' types + /// + /// If more than 1 matching methods are found in the list. + /// + private static MethodBase GetMethodBaseByArgumentValues(string methodTypeName, MethodBase[] methods, + object[] argValues) + { + MethodBase match = null; + int matchCount = 0; + + foreach (MethodBase m in methods) + { + ParameterInfo[] parameters = m.GetParameters(); + bool isMatch = true; + bool isExactMatch = true; + object[] paramValues = (argValues == null) ? new object[0] : argValues; + + try + { + if (parameters.Length > 0) + { + ParameterInfo lastParameter = parameters[parameters.Length - 1]; + if (lastParameter.GetCustomAttributes(typeof(ParamArrayAttribute), false).Length > 0) + { + paramValues = + PackageParamArray(argValues, parameters.Length, + lastParameter.ParameterType.GetElementType()); + } + } + + if (parameters.Length != paramValues.Length) { isMatch = false; - } - else - { - for (int i = 0; i < parameters.Length; i++) - { - Type paramType = parameters[i].ParameterType; - object paramValue = paramValues[i]; - if ((paramValue == null && paramType.IsValueType) - || (paramValue != null && !paramType.IsAssignableFrom(paramValue.GetType()))) - { - isMatch = false; - break; - } - if (paramValue == null || paramType != paramValue.GetType()) - { - isExactMatch = false; - } - } - } - } - catch (InvalidCastException) - { - isMatch = false; - } - - if (isMatch) - { - if (isExactMatch) - { - return m; - } - - matchCount++; - if (matchCount == 1) - { - match = m; - } - else - { - throw new AmbiguousMatchException( - string.Format("Ambiguous match for {0} '{1}' for the specified number and types of arguments.", methodTypeName, - m.Name)); - } - } - } - - return match; - } - - /// - /// From a given list of constructors, selects the constructor having an exact match on the given ' types. - /// - /// the list of constructors to choose from - /// the arguments to the method - /// the constructor matching exactly the passed ' types - /// - /// If more than 1 matching methods are found in the list. - /// - public static ConstructorInfo GetConstructorByArgumentValues(ConstructorInfo[] methods, object[] argValues) - { - return (ConstructorInfo)GetMethodBaseByArgumentValues("constructor", methods, argValues); - } - - - /// - /// Packages arguments into argument list containing parameter array as a last argument. - /// - /// Argument vaklues to package. - /// Total number of oarameters. - /// Type of the param array element. - /// Packaged arguments. - public static object[] PackageParamArray(object[] argValues, int argCount, Type elementType) - { - object[] values = new object[argCount]; - int i = 0; - - // copy regular arguments - while (i < argCount - 1) - { - values[i] = argValues[i]; - i++; - } - - // package param array into last argument - Array paramArray = Array.CreateInstance(elementType, argValues.Length - i); - int j = 0; - while (i < argValues.Length) - { - paramArray.SetValue(argValues[i++], j++); - } - values[values.Length - 1] = paramArray; - - return values; - } - - /// - /// Convenience method to convert an interface - /// to a array that contains - /// all the interfaces inherited and the specified interface. - /// - /// The interface to convert. - /// An array of interface s. - /// - /// If the specified is not an interface. - /// - /// - /// If is . - /// - public static Type[] ToInterfaceArray(Type intf) - { - AssertUtils.ArgumentNotNull(intf, "intf"); - - if (!intf.IsInterface) - { - throw new ArgumentException( - string.Format(CultureInfo.InvariantCulture, - "[{0}] is a class.", - intf.FullName)); - } - - ArrayList interfaces = new ArrayList(intf.GetInterfaces()); - interfaces.Add(intf); - - return (Type[])interfaces.ToArray(typeof(Type)); - } - - /// - /// Is the supplied the default indexer for the - /// supplied ? - /// - /// - /// The name of the property on the supplied to be checked. - /// - /// - /// The to be checked. - /// - /// - /// if the supplied is the - /// default indexer for the supplied . - /// - /// - /// If the supplied is . - /// - public static bool PropertyIsIndexer(string propertyName, Type type) - { - DefaultMemberAttribute[] attribs = - (DefaultMemberAttribute[])type.GetCustomAttributes(typeof(DefaultMemberAttribute), true); - if (attribs.Length != 0) - { - foreach (DefaultMemberAttribute attrib in attribs) - { - if (attrib.MemberName.Equals(propertyName)) - { - return true; - } - } - } - return false; - } - - /// - /// Is the supplied declared on one of these interfaces? - /// - /// The method to check. - /// The array of interfaces we want to check. - /// - /// if the method is declared on one of these interfaces. - /// - /// - /// If any of the s specified is not an interface. - /// - /// - /// If or any of the specified interfaces is - /// . - /// - public static bool MethodIsOnOneOfTheseInterfaces(MethodBase method, Type[] interfaces) - { - AssertUtils.ArgumentNotNull(method, "method"); - if (interfaces == null) - { - return false; - } - Type[] paramTypes = GetParameterTypes(method.GetParameters()); - for (int i = 0; i < interfaces.Length; i++) - { - Type interfaceType = interfaces[i]; - AssertUtils.ArgumentNotNull(interfaceType, StringUtils.Surround("interfaces[", i, "]")); - if (!interfaceType.IsInterface) - { - throw new ArgumentException(interfaces[i].FullName + " is not an interface"); - } - try - { - MethodInfo mi = interfaceType.GetMethod( - method.Name, - BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly, - null, paramTypes, null); - if (mi != null) - { - // found it... - return true; - } - } - catch - { - // didn't find it, so keep going... - } - } - return false; - } - - /// - /// Returns the default value for the specified - /// - /// - ///

- /// Follows the standard .NET conventions for default values where - /// relevant; for example, all numeric types default to the value - /// 0. - ///

- ///
- /// - /// The to return default value for. - /// - /// - /// The default value for the specified . - /// - /// - /// If the supplied is an enumerated type that - /// has no values. - /// - public static object GetDefaultValue(Type type) - { - if (!type.IsValueType) - { - return null; - } - if (type == typeof(Boolean)) - { - return false; - } - if (type == typeof(DateTime)) - { - return DateTime.MinValue; - } - if (type == typeof(Char)) - { - return Char.MinValue; - } - if (type.IsEnum) - { - Array values = Enum.GetValues(type); - if (values == null || values.Length == 0) - { - throw new ArgumentException("Bad 'enum' Type : cannot get default value because 'enum' has no values."); - } - return values.GetValue(0); - } - return 0; - } - - /// - /// Returns an array consisting of the default values for the supplied - /// . - /// - /// - /// The array of s to return default values for. - /// - /// - /// An array consisting of the default values for the supplied - /// . - /// - /// - /// If any of the elements in the supplied - /// array is an enumerated type that has no values. - /// - /// - public static object[] GetDefaultValues(Type[] types) - { - object[] defaults = new object[types.Length]; - for (int i = 0; i < types.Length; ++i) - { - defaults[i] = GetDefaultValue(types[i]); - } - return defaults; - } - - /// - /// Checks that the parameter s of the - /// supplied match the parameter - /// s of the supplied - /// . - /// - /// The method to be checked. - /// - /// The array of parameter s to check against. - /// - /// - /// if the parameter s - /// match. - /// - public static bool ParameterTypesMatch( - MethodInfo candidate, Type[] parameterTypes) - { - #region Sanity Checks - - AssertUtils.ArgumentNotNull(candidate, "candidate"); - AssertUtils.ArgumentNotNull(parameterTypes, "parameterTypes"); - - #endregion - - Type[] candidatesParameterTypes - = ReflectionUtils.GetParameterTypes(candidate); - if (candidatesParameterTypes.Length != parameterTypes.Length) - { - return false; - } - for (int i = 0; i < candidatesParameterTypes.Length; ++i) - { - if (!candidatesParameterTypes[i].Equals(parameterTypes[i])) - { - return false; - } - } - return true; - } - - /// - /// Returns an array containing the s of the - /// objects in the supplied array. - /// - /// - /// The objects array for which the corresponding s - /// are needed. - /// - /// - /// An array containing the s of the objects - /// in the supplied array; this array will be empty (but not - /// if the supplied - /// is null or has no elements. - /// - /// - ///

- /// [C#]
- /// Given an array containing the following objects, - /// [83, "Foo", new object ()], the - /// array returned from this method call would consist of the following - /// elements... - /// [Int32, String, Object]. - ///

- ///
- public static Type[] GetTypes(object[] args) - { - if (args == null || args.Length == 0) - { - return Type.EmptyTypes; - } - Type[] paramsType = new Type[args.Length]; - for (int i = 0; i < args.Length; ++i) - { - object arg = args[i]; - paramsType[i] = (arg != null) ? args[i].GetType() : typeof(object); - } - return paramsType; - } - - /// - /// Does the given and/or it's superclasses - /// have at least one or more methods with the given name (with any - /// argument types)? - /// - /// - ///

- /// Includes non-public methods in the methods searched. - ///

- ///
- /// - /// The to be checked. - /// - /// - /// The name of the method to be searched for. Case inSenSItivE. - /// - /// - /// if the given or / and it's - /// superclasses have at least one or more methods (with any argument types); - /// if not, or either of the parameters is . - /// - public static bool HasAtLeastOneMethodWithName(Type type, string name) - { - if (type == null || StringUtils.IsNullOrEmpty(name)) - { - return false; - } - return MethodCountForName(type, name) > 0; - } - - /// - /// Within , counts the number of overloads for the method with the given (case-insensitive!) - /// - /// The type to be searched - /// the name of the method for which overloads shall be counted - /// The number of overloads for method within type - public static int MethodCountForName(Type type, string name) - { - AssertUtils.ArgumentNotNull(type, "type", "Type must not be null"); - AssertUtils.ArgumentNotNull(name, "name", "Method name must not be null"); - MemberInfo[] methods = type.FindMembers( - MemberTypes.Method, - ReflectionUtils.AllMembersCaseInsensitiveFlags, - new MemberFilter(ReflectionUtils.MethodNameFilter), - name); - return methods.Length; - } - - private static bool MethodNameFilter(MemberInfo member, object criteria) - { - MethodInfo method = member as MethodInfo; - string name = criteria as string; - return String.Compare(method.Name, name, true, CultureInfo.InvariantCulture) == 0; - } - - /// - /// Creates a . - /// - /// - ///

- /// Note that if a non- - /// is supplied, any read write properties exposed by the - /// will be used to overwrite values that may have been passed in via the - /// . That is, the will be used - /// to initialize the custom attribute, and then any read-write properties on the - /// will be plugged in. - ///

- ///
- /// - /// The desired . - /// - /// - /// Any constructor arguments for the attribute (may be - /// in the case of no arguments). - /// - /// - /// Source attribute to copy properties from (may be ). - /// - /// A custom attribute builder. - /// - /// If the parameter is . - /// - /// - /// If the parameter is not a - /// that derives from the class. - /// - /// - public static CustomAttributeBuilder CreateCustomAttribute( - Type type, object[] ctorArgs, Attribute sourceAttribute) - { - #region Sanity Checks - - AssertUtils.ArgumentNotNull(type, "type"); - if (!typeof(Attribute).IsAssignableFrom(type)) - { - throw new ArgumentException( - string.Format("[{0}] does not derive from the [System.Attribute] class.", - type.FullName)); - } - - #endregion - - ConstructorInfo ci = type.GetConstructor(ReflectionUtils.GetTypes(ctorArgs)); - if (ci == null && ctorArgs.Length == 0) - { - ci = type.GetConstructors()[0]; - ctorArgs = GetDefaultValues(GetParameterTypes(ci.GetParameters())); - } - - if (sourceAttribute != null) - { - object defaultAttribute = null; - try - { - defaultAttribute = ci.Invoke(ctorArgs); - } - catch - { - } - - IList getSetProps = new ArrayList(); - IList getSetValues = new ArrayList(); - IList readOnlyProps = new ArrayList(); - IList readOnlyValues = new ArrayList(); - foreach (PropertyInfo pi in type.GetProperties(BindingFlags.Instance | BindingFlags.Public)) - { - if (pi.DeclaringType == typeof(Attribute)) - continue; - - if (pi.CanRead) - { - if (pi.CanWrite) - { - object propValue = pi.GetValue(sourceAttribute, null); - if (defaultAttribute != null) - { - object defaultValue = pi.GetValue(defaultAttribute, null); - if ((propValue == null && defaultValue == null) || - (propValue != null && propValue.Equals(defaultValue))) - continue; - } - getSetProps.Add(pi); - getSetValues.Add(propValue); - } - else - { - readOnlyProps.Add(pi); - readOnlyValues.Add(pi.GetValue(sourceAttribute, null)); - } - } - } - - if (readOnlyProps.Count == 1) - { - PropertyInfo pi = readOnlyProps[0] as PropertyInfo; - ConstructorInfo ciTemp = type.GetConstructor(new Type[1] { pi.PropertyType }); - if (ciTemp != null) - { - ci = ciTemp; - ctorArgs = new object[1] { readOnlyValues[0] }; - } - else - { - ciTemp = type.GetConstructor(new Type[1] { readOnlyValues[0].GetType() }); - if (ciTemp != null) - { - ci = ciTemp; - ctorArgs = new object[1] { readOnlyValues[0] }; - } - } - } - - PropertyInfo[] propertyInfos = new PropertyInfo[getSetProps.Count]; - getSetProps.CopyTo(propertyInfos, 0); - - object[] propertyValues = new object[getSetValues.Count]; - getSetValues.CopyTo(propertyValues, 0); - - return new CustomAttributeBuilder(ci, ctorArgs, propertyInfos, propertyValues); - } - else - { - return new CustomAttributeBuilder(ci, ctorArgs); - } - } - - /// - /// Creates a . - /// - /// - /// The desired . - /// - /// - /// Source attribute to copy properties from (may be ). - /// - /// A custom attribute builder. - public static CustomAttributeBuilder CreateCustomAttribute( - Type type, Attribute sourceAttribute) - { - return CreateCustomAttribute(type, new object[] { }, sourceAttribute); - } - - /// - /// Creates a . - /// - /// - /// The source attribute to copy properties from. - /// - /// A custom attribute builder. - /// - /// If the supplied is - /// . - /// - public static CustomAttributeBuilder CreateCustomAttribute(Attribute sourceAttribute) - { - return CreateCustomAttribute(sourceAttribute.GetType(), sourceAttribute); - } - - /// - /// Creates a . - /// - /// - /// The desired . - /// - /// A custom attribute builder. - public static CustomAttributeBuilder CreateCustomAttribute(Type type) - { - return CreateCustomAttribute(type, new object[] { }, null); - } - - /// - /// Creates a . - /// - /// - /// The desired . - /// - /// - /// Any constructor arguments for the attribute (may be - /// in the case of no arguments). - /// - /// A custom attribute builder. - public static CustomAttributeBuilder CreateCustomAttribute( - Type type, params object[] ctorArgs) - { - return CreateCustomAttribute(type, ctorArgs, null); - } - -#if NET_2_0 - /// - /// Creates a . - /// - /// - /// The to create - /// the custom attribute builder from. - /// - /// A custom attribute builder. - public static CustomAttributeBuilder CreateCustomAttribute(CustomAttributeData attributeData) - { - object[] parameterValues = new object[attributeData.ConstructorArguments.Count]; - Type[] parameterTypes = new Type[attributeData.ConstructorArguments.Count]; - - IList namedParameterValues = new ArrayList(); - IList namedFieldValues = new ArrayList(); - - // Fill arrays of the constructor parameters - for (int i = 0; i < attributeData.ConstructorArguments.Count; i++) - { - parameterTypes[i] = attributeData.ConstructorArguments[i].ArgumentType; - parameterValues[i] = ConvertValueIfNecessary(attributeData.ConstructorArguments[i].Value); - } - - Type attributeType = attributeData.Constructor.DeclaringType; - PropertyInfo[] attributeProperties = attributeType.GetProperties( - BindingFlags.Instance | BindingFlags.Public); - FieldInfo[] attributeFields = attributeType.GetFields( - BindingFlags.Instance | BindingFlags.Public); - - // Not using generics bellow as probably Spring.NET tries to keep - // it on .NET1 compatibility level right now I believe (SD) - // In case of using List the above note makes - // no sense (SD:) - IList propertiesToSet = new ArrayList(); - int k = 0; - - IList fieldsToSet = new ArrayList(); - int n = 0; - - - // Fills arrays of the constructor named parameters - foreach (CustomAttributeNamedArgument namedArgument in attributeData.NamedArguments) - { - bool noMatchingProperty = false; - - // Now iterate through all of the PropertyInfo, find the - // one with the corresponding to the NamedProperty name - // and add it to the array of properties to set. - for (int j = 0; j < attributeProperties.Length; j++) - { - if (attributeProperties[j].Name == namedArgument.MemberInfo.Name) - { - propertiesToSet.Add(attributeProperties[j]); - namedParameterValues.Add(ConvertValueIfNecessary(namedArgument.TypedValue.Value)); - break; - } - else - { - if (j == attributeProperties.Length - 1) - { - // In case of no match, throw - noMatchingProperty = true; + } + else + { + for (int i = 0; i < parameters.Length; i++) + { + Type paramType = parameters[i].ParameterType; + object paramValue = paramValues[i]; + if ((paramValue == null && paramType.IsValueType) + || (paramValue != null && !paramType.IsAssignableFrom(paramValue.GetType()))) + { + isMatch = false; + break; + } + if (paramValue == null || paramType != paramValue.GetType()) + { + isExactMatch = false; + } + } + } + } + catch (InvalidCastException) + { + isMatch = false; + } + + if (isMatch) + { + if (isExactMatch) + { + return m; + } + + matchCount++; + if (matchCount == 1) + { + match = m; + } + else + { + throw new AmbiguousMatchException( + string.Format("Ambiguous match for {0} '{1}' for the specified number and types of arguments.", methodTypeName, + m.Name)); + } + } + } + + return match; + } + + /// + /// From a given list of constructors, selects the constructor having an exact match on the given ' types. + /// + /// the list of constructors to choose from + /// the arguments to the method + /// the constructor matching exactly the passed ' types + /// + /// If more than 1 matching methods are found in the list. + /// + public static ConstructorInfo GetConstructorByArgumentValues(ConstructorInfo[] methods, object[] argValues) + { + return (ConstructorInfo)GetMethodBaseByArgumentValues("constructor", methods, argValues); + } + + + /// + /// Packages arguments into argument list containing parameter array as a last argument. + /// + /// Argument vaklues to package. + /// Total number of oarameters. + /// Type of the param array element. + /// Packaged arguments. + public static object[] PackageParamArray(object[] argValues, int argCount, Type elementType) + { + object[] values = new object[argCount]; + int i = 0; + + // copy regular arguments + while (i < argCount - 1) + { + values[i] = argValues[i]; + i++; + } + + // package param array into last argument + Array paramArray = Array.CreateInstance(elementType, argValues.Length - i); + int j = 0; + while (i < argValues.Length) + { + paramArray.SetValue(argValues[i++], j++); + } + values[values.Length - 1] = paramArray; + + return values; + } + + /// + /// Convenience method to convert an interface + /// to a array that contains + /// all the interfaces inherited and the specified interface. + /// + /// The interface to convert. + /// An array of interface s. + /// + /// If the specified is not an interface. + /// + /// + /// If is . + /// + public static Type[] ToInterfaceArray(Type intf) + { + AssertUtils.ArgumentNotNull(intf, "intf"); + + if (!intf.IsInterface) + { + throw new ArgumentException( + string.Format(CultureInfo.InvariantCulture, + "[{0}] is a class.", + intf.FullName)); + } + + ArrayList interfaces = new ArrayList(intf.GetInterfaces()); + interfaces.Add(intf); + + return (Type[])interfaces.ToArray(typeof(Type)); + } + + /// + /// Is the supplied the default indexer for the + /// supplied ? + /// + /// + /// The name of the property on the supplied to be checked. + /// + /// + /// The to be checked. + /// + /// + /// if the supplied is the + /// default indexer for the supplied . + /// + /// + /// If the supplied is . + /// + public static bool PropertyIsIndexer(string propertyName, Type type) + { + DefaultMemberAttribute[] attribs = + (DefaultMemberAttribute[])type.GetCustomAttributes(typeof(DefaultMemberAttribute), true); + if (attribs.Length != 0) + { + foreach (DefaultMemberAttribute attrib in attribs) + { + if (attrib.MemberName.Equals(propertyName)) + { + return true; + } + } + } + return false; + } + + /// + /// Is the supplied declared on one of these interfaces? + /// + /// The method to check. + /// The array of interfaces we want to check. + /// + /// if the method is declared on one of these interfaces. + /// + /// + /// If any of the s specified is not an interface. + /// + /// + /// If or any of the specified interfaces is + /// . + /// + public static bool MethodIsOnOneOfTheseInterfaces(MethodBase method, Type[] interfaces) + { + AssertUtils.ArgumentNotNull(method, "method"); + if (interfaces == null) + { + return false; + } + Type[] paramTypes = GetParameterTypes(method.GetParameters()); + for (int i = 0; i < interfaces.Length; i++) + { + Type interfaceType = interfaces[i]; + AssertUtils.ArgumentNotNull(interfaceType, StringUtils.Surround("interfaces[", i, "]")); + if (!interfaceType.IsInterface) + { + throw new ArgumentException(interfaces[i].FullName + " is not an interface"); + } + try + { + MethodInfo mi = interfaceType.GetMethod( + method.Name, + BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly, + null, paramTypes, null); + if (mi != null) + { + // found it... + return true; + } + } + catch + { + // didn't find it, so keep going... + } + } + return false; + } + + /// + /// Returns the default value for the specified + /// + /// + ///

+ /// Follows the standard .NET conventions for default values where + /// relevant; for example, all numeric types default to the value + /// 0. + ///

+ ///
+ /// + /// The to return default value for. + /// + /// + /// The default value for the specified . + /// + /// + /// If the supplied is an enumerated type that + /// has no values. + /// + public static object GetDefaultValue(Type type) + { + if (!type.IsValueType) + { + return null; + } + if (type == typeof(Boolean)) + { + return false; + } + if (type == typeof(DateTime)) + { + return DateTime.MinValue; + } + if (type == typeof(Char)) + { + return Char.MinValue; + } + if (type.IsEnum) + { + Array values = Enum.GetValues(type); + if (values == null || values.Length == 0) + { + throw new ArgumentException("Bad 'enum' Type : cannot get default value because 'enum' has no values."); + } + return values.GetValue(0); + } + return 0; + } + + /// + /// Returns an array consisting of the default values for the supplied + /// . + /// + /// + /// The array of s to return default values for. + /// + /// + /// An array consisting of the default values for the supplied + /// . + /// + /// + /// If any of the elements in the supplied + /// array is an enumerated type that has no values. + /// + /// + public static object[] GetDefaultValues(Type[] types) + { + object[] defaults = new object[types.Length]; + for (int i = 0; i < types.Length; ++i) + { + defaults[i] = GetDefaultValue(types[i]); + } + return defaults; + } + + /// + /// Checks that the parameter s of the + /// supplied match the parameter + /// s of the supplied + /// . + /// + /// The method to be checked. + /// + /// The array of parameter s to check against. + /// + /// + /// if the parameter s + /// match. + /// + public static bool ParameterTypesMatch( + MethodInfo candidate, Type[] parameterTypes) + { + #region Sanity Checks + + AssertUtils.ArgumentNotNull(candidate, "candidate"); + AssertUtils.ArgumentNotNull(parameterTypes, "parameterTypes"); + + #endregion + + Type[] candidatesParameterTypes + = ReflectionUtils.GetParameterTypes(candidate); + if (candidatesParameterTypes.Length != parameterTypes.Length) + { + return false; + } + for (int i = 0; i < candidatesParameterTypes.Length; ++i) + { + if (!candidatesParameterTypes[i].Equals(parameterTypes[i])) + { + return false; + } + } + return true; + } + + /// + /// Returns an array containing the s of the + /// objects in the supplied array. + /// + /// + /// The objects array for which the corresponding s + /// are needed. + /// + /// + /// An array containing the s of the objects + /// in the supplied array; this array will be empty (but not + /// if the supplied + /// is null or has no elements. + /// + /// + ///

+ /// [C#]
+ /// Given an array containing the following objects, + /// [83, "Foo", new object ()], the + /// array returned from this method call would consist of the following + /// elements... + /// [Int32, String, Object]. + ///

+ ///
+ public static Type[] GetTypes(object[] args) + { + if (args == null || args.Length == 0) + { + return Type.EmptyTypes; + } + Type[] paramsType = new Type[args.Length]; + for (int i = 0; i < args.Length; ++i) + { + object arg = args[i]; + paramsType[i] = (arg != null) ? args[i].GetType() : typeof(object); + } + return paramsType; + } + + /// + /// Does the given and/or it's superclasses + /// have at least one or more methods with the given name (with any + /// argument types)? + /// + /// + ///

+ /// Includes non-public methods in the methods searched. + ///

+ ///
+ /// + /// The to be checked. + /// + /// + /// The name of the method to be searched for. Case inSenSItivE. + /// + /// + /// if the given or / and it's + /// superclasses have at least one or more methods (with any argument types); + /// if not, or either of the parameters is . + /// + public static bool HasAtLeastOneMethodWithName(Type type, string name) + { + if (type == null || StringUtils.IsNullOrEmpty(name)) + { + return false; + } + return MethodCountForName(type, name) > 0; + } + + /// + /// Within , counts the number of overloads for the method with the given (case-insensitive!) + /// + /// The type to be searched + /// the name of the method for which overloads shall be counted + /// The number of overloads for method within type + public static int MethodCountForName(Type type, string name) + { + AssertUtils.ArgumentNotNull(type, "type", "Type must not be null"); + AssertUtils.ArgumentNotNull(name, "name", "Method name must not be null"); + MemberInfo[] methods = type.FindMembers( + MemberTypes.Method, + ReflectionUtils.AllMembersCaseInsensitiveFlags, + new MemberFilter(ReflectionUtils.MethodNameFilter), + name); + return methods.Length; + } + + private static bool MethodNameFilter(MemberInfo member, object criteria) + { + MethodInfo method = member as MethodInfo; + string name = criteria as string; + return String.Compare(method.Name, name, true, CultureInfo.InvariantCulture) == 0; + } + + /// + /// Creates a . + /// + /// + ///

+ /// Note that if a non- + /// is supplied, any read write properties exposed by the + /// will be used to overwrite values that may have been passed in via the + /// . That is, the will be used + /// to initialize the custom attribute, and then any read-write properties on the + /// will be plugged in. + ///

+ ///
+ /// + /// The desired . + /// + /// + /// Any constructor arguments for the attribute (may be + /// in the case of no arguments). + /// + /// + /// Source attribute to copy properties from (may be ). + /// + /// A custom attribute builder. + /// + /// If the parameter is . + /// + /// + /// If the parameter is not a + /// that derives from the class. + /// + /// + public static CustomAttributeBuilder CreateCustomAttribute( + Type type, object[] ctorArgs, Attribute sourceAttribute) + { + #region Sanity Checks + + AssertUtils.ArgumentNotNull(type, "type"); + if (!typeof(Attribute).IsAssignableFrom(type)) + { + throw new ArgumentException( + string.Format("[{0}] does not derive from the [System.Attribute] class.", + type.FullName)); + } + + #endregion + + ConstructorInfo ci = type.GetConstructor(ReflectionUtils.GetTypes(ctorArgs)); + if (ci == null && ctorArgs.Length == 0) + { + ci = type.GetConstructors()[0]; + ctorArgs = GetDefaultValues(GetParameterTypes(ci.GetParameters())); + } + + if (sourceAttribute != null) + { + object defaultAttribute = null; + try + { + defaultAttribute = ci.Invoke(ctorArgs); + } + catch + { + } + + IList getSetProps = new ArrayList(); + IList getSetValues = new ArrayList(); + IList readOnlyProps = new ArrayList(); + IList readOnlyValues = new ArrayList(); + foreach (PropertyInfo pi in type.GetProperties(BindingFlags.Instance | BindingFlags.Public)) + { + if (pi.DeclaringType == typeof(Attribute)) + continue; + + if (pi.CanRead) + { + if (pi.CanWrite) + { + object propValue = pi.GetValue(sourceAttribute, null); + if (defaultAttribute != null) + { + object defaultValue = pi.GetValue(defaultAttribute, null); + if ((propValue == null && defaultValue == null) || + (propValue != null && propValue.Equals(defaultValue))) + continue; + } + getSetProps.Add(pi); + getSetValues.Add(propValue); + } + else + { + readOnlyProps.Add(pi); + readOnlyValues.Add(pi.GetValue(sourceAttribute, null)); + } + } + } + + if (readOnlyProps.Count == 1) + { + PropertyInfo pi = readOnlyProps[0] as PropertyInfo; + ConstructorInfo ciTemp = type.GetConstructor(new Type[1] { pi.PropertyType }); + if (ciTemp != null) + { + ci = ciTemp; + ctorArgs = new object[1] { readOnlyValues[0] }; + } + else + { + ciTemp = type.GetConstructor(new Type[1] { readOnlyValues[0].GetType() }); + if (ciTemp != null) + { + ci = ciTemp; + ctorArgs = new object[1] { readOnlyValues[0] }; + } + } + } + + PropertyInfo[] propertyInfos = new PropertyInfo[getSetProps.Count]; + getSetProps.CopyTo(propertyInfos, 0); + + object[] propertyValues = new object[getSetValues.Count]; + getSetValues.CopyTo(propertyValues, 0); + + return new CustomAttributeBuilder(ci, ctorArgs, propertyInfos, propertyValues); + } + else + { + return new CustomAttributeBuilder(ci, ctorArgs); + } + } + + /// + /// Creates a . + /// + /// + /// The desired . + /// + /// + /// Source attribute to copy properties from (may be ). + /// + /// A custom attribute builder. + public static CustomAttributeBuilder CreateCustomAttribute( + Type type, Attribute sourceAttribute) + { + return CreateCustomAttribute(type, new object[] { }, sourceAttribute); + } + + /// + /// Creates a . + /// + /// + /// The source attribute to copy properties from. + /// + /// A custom attribute builder. + /// + /// If the supplied is + /// . + /// + public static CustomAttributeBuilder CreateCustomAttribute(Attribute sourceAttribute) + { + return CreateCustomAttribute(sourceAttribute.GetType(), sourceAttribute); + } + + /// + /// Creates a . + /// + /// + /// The desired . + /// + /// A custom attribute builder. + public static CustomAttributeBuilder CreateCustomAttribute(Type type) + { + return CreateCustomAttribute(type, new object[] { }, null); + } + + /// + /// Creates a . + /// + /// + /// The desired . + /// + /// + /// Any constructor arguments for the attribute (may be + /// in the case of no arguments). + /// + /// A custom attribute builder. + public static CustomAttributeBuilder CreateCustomAttribute( + Type type, params object[] ctorArgs) + { + return CreateCustomAttribute(type, ctorArgs, null); + } + +#if NET_2_0 + /// + /// Creates a . + /// + /// + /// The to create + /// the custom attribute builder from. + /// + /// A custom attribute builder. + public static CustomAttributeBuilder CreateCustomAttribute(CustomAttributeData attributeData) + { + object[] parameterValues = new object[attributeData.ConstructorArguments.Count]; + Type[] parameterTypes = new Type[attributeData.ConstructorArguments.Count]; + + IList namedParameterValues = new ArrayList(); + IList namedFieldValues = new ArrayList(); + + // Fill arrays of the constructor parameters + for (int i = 0; i < attributeData.ConstructorArguments.Count; i++) + { + parameterTypes[i] = attributeData.ConstructorArguments[i].ArgumentType; + parameterValues[i] = ConvertValueIfNecessary(attributeData.ConstructorArguments[i].Value); + } + + Type attributeType = attributeData.Constructor.DeclaringType; + PropertyInfo[] attributeProperties = attributeType.GetProperties( + BindingFlags.Instance | BindingFlags.Public); + FieldInfo[] attributeFields = attributeType.GetFields( + BindingFlags.Instance | BindingFlags.Public); + + // Not using generics bellow as probably Spring.NET tries to keep + // it on .NET1 compatibility level right now I believe (SD) + // In case of using List the above note makes + // no sense (SD:) + IList propertiesToSet = new ArrayList(); + int k = 0; + + IList fieldsToSet = new ArrayList(); + int n = 0; + + + // Fills arrays of the constructor named parameters + foreach (CustomAttributeNamedArgument namedArgument in attributeData.NamedArguments) + { + bool noMatchingProperty = false; + + // Now iterate through all of the PropertyInfo, find the + // one with the corresponding to the NamedProperty name + // and add it to the array of properties to set. + for (int j = 0; j < attributeProperties.Length; j++) + { + if (attributeProperties[j].Name == namedArgument.MemberInfo.Name) + { + propertiesToSet.Add(attributeProperties[j]); + namedParameterValues.Add(ConvertValueIfNecessary(namedArgument.TypedValue.Value)); + break; + } + else + { + if (j == attributeProperties.Length - 1) + { + // In case of no match, throw + noMatchingProperty = true; /* throw new InvalidOperationException( String.Format(CultureInfo.InvariantCulture, @@ -977,388 +984,396 @@ namespace Spring.Util "type {1}, but is present as a named property " + "on the attributeData {2}", namedArgument.MemberInfo.Name, attributeType.FullName, attributeData)); - */ - } - } - } - if (noMatchingProperty) - { - for (int j = 0; j < attributeFields.Length; j++) - { - if (attributeFields[j].Name == namedArgument.MemberInfo.Name) - { - fieldsToSet.Add(attributeFields[j]); - namedFieldValues.Add(ConvertValueIfNecessary(namedArgument.TypedValue.Value)); - break; - } - else - { - if (j == attributeFields.Length - 1) - { - throw new InvalidOperationException( - String.Format(CultureInfo.InvariantCulture, - "A property or public field with name {0} can't be found in the " + - "type {1}, but is present as a named property " + - "on the attributeData {2}", namedArgument.MemberInfo.Name, - attributeType.FullName, attributeData)); - } - } - } - } - } - // Get constructor corresponding to the parameters and their types - ConstructorInfo constructor = attributeType.GetConstructor(parameterTypes); - - PropertyInfo[] namedProperties = new PropertyInfo[propertiesToSet.Count]; - propertiesToSet.CopyTo(namedProperties, 0); - - object[] propertyValues = new object[namedParameterValues.Count]; - namedParameterValues.CopyTo(propertyValues, 0); - - if (fieldsToSet.Count == 0) - { - return new CustomAttributeBuilder( - constructor, parameterValues, namedProperties, propertyValues); - } - else - { - FieldInfo[] namedFields = new FieldInfo[fieldsToSet.Count]; - fieldsToSet.CopyTo(namedFields, 0); - - object[] fieldValues = new object[namedFieldValues.Count]; - namedFieldValues.CopyTo(fieldValues, 0); - - return new CustomAttributeBuilder( - constructor, parameterValues, namedProperties, propertyValues, namedFields, fieldValues); - } - - - - } - - private static object ConvertValueIfNecessary(object value) - { - if (value == null) return value; - - // We are only hunting for the case of the ReadOnlyCollection here. - ReadOnlyCollection sourceArray = - value as ReadOnlyCollection; - - if (sourceArray == null) return value; - - Type underlyingType = null; // type to be used for arguments - Array returnArray = null; - for (int i = 0; i < sourceArray.Count; i++) - { - if (underlyingType == null) - { - underlyingType = sourceArray[i].ArgumentType; - returnArray = Array.CreateInstance(underlyingType, sourceArray.Count); - } - if (!underlyingType.Equals(sourceArray[i].ArgumentType)) - { - throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, - "Types for the same named parameter of array type are expected to be same")); - } - - returnArray.SetValue(sourceArray[i].Value, i); - } - - return returnArray; - - } -#endif - - /// - /// Tries to find matching methods in the specified - /// for each method in the supplied list. - /// - /// - /// The to look for matching methods in. - /// - /// The methods to match. - /// - /// A flag that specifies whether to throw an exception if a matching - /// method is not found. - /// - /// A list of the matched methods. - /// - /// If either of the or - /// parameters are . - /// - public static MethodInfo[] GetMatchingMethods(Type type, MethodInfo[] methods, bool strict) - { - AssertUtils.ArgumentNotNull(type, "type"); - AssertUtils.ArgumentNotNull(methods, "methods"); - - BindingFlags flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase; - - MethodInfo[] matched = new MethodInfo[methods.Length]; - for (int i = 0; i < methods.Length; i++) - { - MethodInfo method = methods[i]; - MethodInfo match = type.GetMethod(method.Name, flags, null, ReflectionUtils.GetParameterTypes(method), null); - if ((match == null || match.ReturnType != method.ReturnType) && strict) - { - throw new Exception( - string.Format("Method '{0}' could not be matched in the target class [{1}].", - method.Name, type.FullName)); - } - matched[i] = match; - } - return matched; - } - - /// - /// Returns the of the supplied - /// . - /// - /// - ///

- /// If the is a - /// instance, the return value of this method call with be the - /// parameter cast to a - /// . If the is - /// anything other than a , the return value - /// will be the result of invoking the 's - /// method. - ///

- ///
- /// - /// A or instance. - /// - /// - /// The argument if it is a - /// or the result of invoking - /// on the argument if it - /// is an . - /// - /// - /// If the is . - /// - public static Type TypeOfOrType(object source) - { - return source is Type ? source as Type : source.GetType(); - } - - -#if NET_2_0 - private static readonly MethodInfo Exception_InternalPreserveStackTrace = - typeof(Exception).GetMethod("InternalPreserveStackTrace", BindingFlags.Instance | BindingFlags.NonPublic); + */ + } + } + } + if (noMatchingProperty) + { + for (int j = 0; j < attributeFields.Length; j++) + { + if (attributeFields[j].Name == namedArgument.MemberInfo.Name) + { + fieldsToSet.Add(attributeFields[j]); + namedFieldValues.Add(ConvertValueIfNecessary(namedArgument.TypedValue.Value)); + break; + } + else + { + if (j == attributeFields.Length - 1) + { + throw new InvalidOperationException( + String.Format(CultureInfo.InvariantCulture, + "A property or public field with name {0} can't be found in the " + + "type {1}, but is present as a named property " + + "on the attributeData {2}", namedArgument.MemberInfo.Name, + attributeType.FullName, attributeData)); + } + } + } + } + } + // Get constructor corresponding to the parameters and their types + ConstructorInfo constructor = attributeType.GetConstructor(parameterTypes); + + PropertyInfo[] namedProperties = new PropertyInfo[propertiesToSet.Count]; + propertiesToSet.CopyTo(namedProperties, 0); + + object[] propertyValues = new object[namedParameterValues.Count]; + namedParameterValues.CopyTo(propertyValues, 0); + + if (fieldsToSet.Count == 0) + { + return new CustomAttributeBuilder( + constructor, parameterValues, namedProperties, propertyValues); + } + else + { + FieldInfo[] namedFields = new FieldInfo[fieldsToSet.Count]; + fieldsToSet.CopyTo(namedFields, 0); + + object[] fieldValues = new object[namedFieldValues.Count]; + namedFieldValues.CopyTo(fieldValues, 0); + + return new CustomAttributeBuilder( + constructor, parameterValues, namedProperties, propertyValues, namedFields, fieldValues); + } + + + + } + + private static object ConvertValueIfNecessary(object value) + { + if (value == null) + return value; + + // We are only hunting for the case of the ReadOnlyCollection here. + ReadOnlyCollection sourceArray = + value as ReadOnlyCollection; + + if (sourceArray == null) + return value; + + Type underlyingType = null; // type to be used for arguments + Array returnArray = null; + for (int i = 0; i < sourceArray.Count; i++) + { + if (underlyingType == null) + { + underlyingType = sourceArray[i].ArgumentType; + returnArray = Array.CreateInstance(underlyingType, sourceArray.Count); + } + if (!underlyingType.Equals(sourceArray[i].ArgumentType)) + { + throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, + "Types for the same named parameter of array type are expected to be same")); + } + + returnArray.SetValue(sourceArray[i].Value, i); + } + + return returnArray; + + } +#endif + + /// + /// Tries to find matching methods in the specified + /// for each method in the supplied list. + /// + /// + /// The to look for matching methods in. + /// + /// The methods to match. + /// + /// A flag that specifies whether to throw an exception if a matching + /// method is not found. + /// + /// A list of the matched methods. + /// + /// If either of the or + /// parameters are . + /// + public static MethodInfo[] GetMatchingMethods(Type type, MethodInfo[] methods, bool strict) + { + AssertUtils.ArgumentNotNull(type, "type"); + AssertUtils.ArgumentNotNull(methods, "methods"); + + BindingFlags flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase; + + MethodInfo[] matched = new MethodInfo[methods.Length]; + for (int i = 0; i < methods.Length; i++) + { + MethodInfo method = methods[i]; + MethodInfo match = type.GetMethod(method.Name, flags, null, ReflectionUtils.GetParameterTypes(method), null); + if ((match == null || match.ReturnType != method.ReturnType) && strict) + { + throw new Exception( + string.Format("Method '{0}' could not be matched in the target class [{1}].", + method.Name, type.FullName)); + } + matched[i] = match; + } + return matched; + } + + /// + /// Returns the of the supplied + /// . + /// + /// + ///

+ /// If the is a + /// instance, the return value of this method call with be the + /// parameter cast to a + /// . If the is + /// anything other than a , the return value + /// will be the result of invoking the 's + /// method. + ///

+ ///
+ /// + /// A or instance. + /// + /// + /// The argument if it is a + /// or the result of invoking + /// on the argument if it + /// is an . + /// + /// + /// If the is . + /// + public static Type TypeOfOrType(object source) + { + return source is Type ? source as Type : source.GetType(); + } + + +#if NET_2_0 + private static readonly MethodInfo Exception_InternalPreserveStackTrace = + typeof(Exception).GetMethod("InternalPreserveStackTrace", BindingFlags.Instance | BindingFlags.NonPublic); #else private static readonly FieldInfo Exception_RemoteStackTraceString = typeof(Exception).GetField("_remoteStackTraceString", BindingFlags.Instance | BindingFlags.NonPublic); -#endif - - /// - /// Unwraps the supplied - /// and returns the inner exception preserving the stack trace. - /// - /// - /// The to unwrap. - /// - /// The unwrapped exception. - public static Exception UnwrapTargetInvocationException(TargetInvocationException ex) - { -#if NET_2_0 - Exception_InternalPreserveStackTrace.Invoke(ex.InnerException, new Object[] { }); +#endif + + /// + /// Unwraps the supplied + /// and returns the inner exception preserving the stack trace. + /// + /// + /// The to unwrap. + /// + /// The unwrapped exception. + public static Exception UnwrapTargetInvocationException(TargetInvocationException ex) + { +#if NET_2_0 + Exception_InternalPreserveStackTrace.Invoke(ex.InnerException, new Object[] { }); #else Exception_RemoteStackTraceString.SetValue(ex.InnerException, ex.InnerException.StackTrace + Environment.NewLine); -#endif - return ex.InnerException; - } - - /// - /// Is the supplied can be accessed outside the assembly ? - /// - /// The type to check. - /// - /// if the type can be accessed outside the assembly; - /// Otherwise . - /// - public static bool IsTypeVisible(Type type) - { - return IsTypeVisible(type, null); - } - - /// - /// Is the supplied can be accessed - /// from the supplied friendly assembly ? - /// - /// The type to check. - /// The friendly assembly name. - /// - /// if the type can be accessed - /// from the supplied friendly assembly; Otherwise . - /// - public static bool IsTypeVisible(Type type, string friendlyAssemblyName) - { -#if NET_2_0 - if (type.IsVisible) - { - return true; - } - else - { - if (friendlyAssemblyName != null - && friendlyAssemblyName.Length > 0 - && (!type.IsNested || type.IsNestedPublic || - (!type.IsNestedPrivate && (type.IsNestedAssembly || type.IsNestedFamORAssem)))) - { - object[] attrs = type.Assembly.GetCustomAttributes(typeof(InternalsVisibleToAttribute), false); - foreach (InternalsVisibleToAttribute ivta in attrs) - { - if (ivta.AssemblyName == friendlyAssemblyName) - { - return true; - } - } - } - } +#endif + return ex.InnerException; + } + + /// + /// Is the supplied can be accessed outside the assembly ? + /// + /// The type to check. + /// + /// if the type can be accessed outside the assembly; + /// Otherwise . + /// + public static bool IsTypeVisible(Type type) + { + return IsTypeVisible(type, null); + } + + /// + /// Is the supplied can be accessed + /// from the supplied friendly assembly ? + /// + /// The type to check. + /// The friendly assembly name. + /// + /// if the type can be accessed + /// from the supplied friendly assembly; Otherwise . + /// + public static bool IsTypeVisible(Type type, string friendlyAssemblyName) + { +#if NET_2_0 + if (type.IsVisible) + { + return true; + } + else + { + if (friendlyAssemblyName != null + && friendlyAssemblyName.Length > 0 + && (!type.IsNested || type.IsNestedPublic || + (!type.IsNestedPrivate && (type.IsNestedAssembly || type.IsNestedFamORAssem)))) + { + object[] attrs = type.Assembly.GetCustomAttributes(typeof(InternalsVisibleToAttribute), false); + foreach (InternalsVisibleToAttribute ivta in attrs) + { + if (ivta.AssemblyName == friendlyAssemblyName) + { + return true; + } + } + } + } #else if (type.IsPublic || (type.IsNestedPublic && type.DeclaringType.IsPublic)) { return true; } -#endif - return false; +#endif + return false; } - /// - /// Gets all of the interfaces implemented by - /// the specified . - /// - /// - /// The object to get the interfaces of. - /// - /// - /// All of the interfaces implemented by the - /// . - /// - public static Type[] GetInterfaces(Type type) - { - AssertUtils.ArgumentNotNull(type, "type"); - - if (type.IsInterface) - { - ArrayList interfaces = new ArrayList(); - interfaces.Add(type); - interfaces.AddRange(type.GetInterfaces()); - return (Type[])interfaces.ToArray(typeof(Type)); - } - else - { - return type.GetInterfaces(); - } - } - - /// - /// Returns the explicit that is the root cause of an exception. - /// - /// - /// If the InnerException property of the current exception is a null reference - /// or a , returns the current exception. - /// - /// The last exception thrown. - /// - /// The first explicit exception thrown in a chain of exceptions. - /// - public static Exception GetExplicitBaseException(Exception ex) - { - Exception innerEx = ex.InnerException; - while (innerEx != null && - !(innerEx is NullReferenceException)) - { - ex = innerEx; - innerEx = innerEx.InnerException; - } - return ex; - } - - /// - /// Copies all fields from one object to another. - /// - /// - /// The types of both objects must be related. This means, that either of the following is true: - /// - /// fromObject.GetType() == toObject.GetType() - /// fromObject.GetType() is derived from toObject.GetType() - /// toObject.GetType() is derived from fromObject.GetType() - /// - /// - /// The source object - /// The object, who's fields will be populated with values from the source object - /// If the object's types are not related - public static void MemberwiseCopy(object fromObject, object toObject) - { - Type fromType = fromObject.GetType(); - Type toType = toObject.GetType(); - - Type smallerType; - - if (fromType.IsAssignableFrom(toType)) - { - smallerType = fromType; - } - else if (toType.IsAssignableFrom(fromType)) - { - smallerType = toType; - } - else - { - throw new ArgumentException("object types are not related"); - } - - MemberwiseCopyInternal(fromObject, toObject, smallerType); - } - -#if NET_2_0 - private static void MemberwiseCopyInternal(object fromObject, object toObject, Type smallerType) - { - MemberwiseCopyHandler impl = GetImpl(smallerType); - impl(fromObject, toObject); - } - - private delegate void MemberwiseCopyHandler(object a, object b); - - private static readonly Hashtable s_handlerCache = new Hashtable(); - - private static MemberwiseCopyHandler GetImpl(Type type) - { - MemberwiseCopyHandler handler = s_handlerCache[type] as MemberwiseCopyHandler; - if (handler != null) return handler; - - lock (s_handlerCache) - { - handler = s_handlerCache[type] as MemberwiseCopyHandler; - if (handler != null) return handler; - - FieldInfo[] fields = GetFields(type); - DynamicMethod dm = new DynamicMethod(type.FullName + ".ShallowCopy", null, new Type[] { typeof(object), typeof(object) }, type.Module, true); - ILGenerator ilGen = dm.GetILGenerator(); - ilGen.DeclareLocal(type); - ilGen.DeclareLocal(type); - ilGen.Emit(OpCodes.Ldarg_0); - ilGen.Emit(OpCodes.Castclass, type); - ilGen.Emit(OpCodes.Stloc_0); - ilGen.Emit(OpCodes.Ldarg_1); - ilGen.Emit(OpCodes.Castclass, type); - ilGen.Emit(OpCodes.Stloc_1); - - foreach (FieldInfo field in fields) - { - ilGen.Emit(OpCodes.Ldloc_1); - ilGen.Emit(OpCodes.Ldloc_0); - ilGen.Emit(OpCodes.Ldfld, field); - ilGen.Emit(OpCodes.Stfld, field); - } - ilGen.Emit(OpCodes.Ret); - - handler = (MemberwiseCopyHandler)dm.CreateDelegate(typeof(MemberwiseCopyHandler)); - s_handlerCache[type] = handler; - } - return handler; - } + /// + /// Gets all of the interfaces implemented by + /// the specified . + /// + /// + /// The object to get the interfaces of. + /// + /// + /// All of the interfaces implemented by the + /// . + /// + public static Type[] GetInterfaces(Type type) + { + AssertUtils.ArgumentNotNull(type, "type"); + + if (type.IsInterface) + { + ArrayList interfaces = new ArrayList(); + interfaces.Add(type); + interfaces.AddRange(type.GetInterfaces()); + return (Type[])interfaces.ToArray(typeof(Type)); + } + else + { + return type.GetInterfaces(); + } + } + + /// + /// Returns the explicit that is the root cause of an exception. + /// + /// + /// If the InnerException property of the current exception is a null reference + /// or a , returns the current exception. + /// + /// The last exception thrown. + /// + /// The first explicit exception thrown in a chain of exceptions. + /// + public static Exception GetExplicitBaseException(Exception ex) + { + Exception innerEx = ex.InnerException; + while (innerEx != null && + !(innerEx is NullReferenceException)) + { + ex = innerEx; + innerEx = innerEx.InnerException; + } + return ex; + } + + /// + /// Copies all fields from one object to another. + /// + /// + /// The types of both objects must be related. This means, that either of the following is true: + /// + /// fromObject.GetType() == toObject.GetType() + /// fromObject.GetType() is derived from toObject.GetType() + /// toObject.GetType() is derived from fromObject.GetType() + /// + /// + /// The source object + /// The object, who's fields will be populated with values from the source object + /// If the object's types are not related + public static void MemberwiseCopy(object fromObject, object toObject) + { + Type fromType = fromObject.GetType(); + Type toType = toObject.GetType(); + + Type smallerType; + + if (fromType.IsAssignableFrom(toType)) + { + smallerType = fromType; + } + else if (toType.IsAssignableFrom(fromType)) + { + smallerType = toType; + } + else + { + throw new ArgumentException("object types are not related"); + } + + MemberwiseCopyInternal(fromObject, toObject, smallerType); + } + +#if NET_2_0 + private static void MemberwiseCopyInternal(object fromObject, object toObject, Type smallerType) + { + MemberwiseCopyHandler impl = GetImpl(smallerType); + impl(fromObject, toObject); + } + + private delegate void MemberwiseCopyHandler(object a, object b); + + private static readonly Hashtable s_handlerCache = new Hashtable(); + + private static MemberwiseCopyHandler GetImpl(Type type) + { + MemberwiseCopyHandler handler = s_handlerCache[type] as MemberwiseCopyHandler; + if (handler != null) + return handler; + + lock (s_handlerCache) + { + handler = s_handlerCache[type] as MemberwiseCopyHandler; + if (handler != null) + return handler; + + FieldInfo[] fields = GetFields(type); + SecurityCritical.ExecutePrivileged(new PermissionSet(PermissionState.Unrestricted), delegate + { + DynamicMethod dm = new DynamicMethod(type.FullName + ".ShallowCopy", null, new Type[] { typeof(object), typeof(object) }, type.Module, true); + ILGenerator ilGen = dm.GetILGenerator(); + ilGen.DeclareLocal(type); + ilGen.DeclareLocal(type); + ilGen.Emit(OpCodes.Ldarg_0); + ilGen.Emit(OpCodes.Castclass, type); + ilGen.Emit(OpCodes.Stloc_0); + ilGen.Emit(OpCodes.Ldarg_1); + ilGen.Emit(OpCodes.Castclass, type); + ilGen.Emit(OpCodes.Stloc_1); + + foreach (FieldInfo field in fields) + { + ilGen.Emit(OpCodes.Ldloc_1); + ilGen.Emit(OpCodes.Ldloc_0); + ilGen.Emit(OpCodes.Ldfld, field); + ilGen.Emit(OpCodes.Stfld, field); + } + ilGen.Emit(OpCodes.Ret); + + handler = (MemberwiseCopyHandler)dm.CreateDelegate(typeof(MemberwiseCopyHandler)); + }); + + s_handlerCache[type] = handler; + } + return handler; + } #else private static void MemberwiseCopyInternal(object fromObject, object toObject, Type smallerType) { @@ -1369,156 +1384,157 @@ namespace Spring.Util field.SetValue(toObject, field.GetValue(fromObject)); } } -#endif - - #region Field Cache Management for "MemberwiseCopy" - - private const BindingFlags FIELDBINDINGS = - BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic; - - private static readonly Hashtable s_fieldCache = new Hashtable(); - - private static FieldInfo[] GetFields(Type type) - { - lock (s_fieldCache) - { - FieldInfo[] fields = (FieldInfo[])s_fieldCache[type]; - if (fields == null) - { - ArrayList fieldList = new ArrayList(); - CollectFieldsRecursive(type, fieldList); - fields = (FieldInfo[])fieldList.ToArray(typeof(FieldInfo)); - s_fieldCache[type] = fields; - } - return fields; - } - } - - private static void CollectFieldsRecursive(Type type, ArrayList fieldList) - { - if (type == typeof(object)) return; - - FieldInfo[] fields = type.GetFields(FIELDBINDINGS); - fieldList.AddRange(fields); - CollectFieldsRecursive(type.BaseType, fieldList); - } - - #endregion Field Cache Management for "MemberwiseCopy" - - - #region CustomAttributeBuilderBuilder inner class definition - - /// - /// Creates a . - /// - /// Bruno Baia - public class CustomAttributeBuilderBuilder - { - #region Fields - - private Type type; - private ArrayList constructorArgs; - private ArrayList namedProperties; - private ArrayList propertyValues; - - #endregion - - #region Constructor(s) / Destructor - - /// - /// Creates a new instance of the - /// class. - /// - /// The custom attribute type. - public CustomAttributeBuilderBuilder(Type attributeType) - : - this(attributeType, ObjectUtils.EmptyObjects) - { - } - - /// - /// Creates a new instance of the - /// class. - /// - /// The custom attribute type. - /// The custom attribute constructor arguments. - public CustomAttributeBuilderBuilder(Type attributeType, params object[] constructorArgs) - { - AssertUtils.ArgumentNotNull(attributeType, "attributeType"); - if (!typeof(Attribute).IsAssignableFrom(attributeType)) - { - throw new ArgumentException( - string.Format("[{0}] does not derive from the [System.Attribute] class.", - attributeType.FullName)); - } - this.type = attributeType; - this.constructorArgs = new ArrayList(constructorArgs); - this.namedProperties = new ArrayList(); - this.propertyValues = new ArrayList(); - } - - #endregion - - #region Public Methods - - /// - /// Adds the specified values to the constructor argument list - /// used to create the custom attribute. - /// - /// An array of argument values. - public void AddContructorArgument(params object[] values) - { - this.constructorArgs.AddRange(values); - } - - /// - /// Adds a property value to the custom attribute. - /// - /// The property name. - /// The property value. - public void AddPropertyValue(string name, object value) - { - PropertyInfo propertyInfo = this.type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public); - if (propertyInfo == null) - { - throw new ArgumentException( - String.Format("The property '{0}' does no exist in the attribute '{1}'.", name, this.type)); - } - - this.namedProperties.Add(propertyInfo); - this.propertyValues.Add(value); - } - - /// - /// Creates the . - /// - /// The created . - public CustomAttributeBuilder Build() - { - object[] caArray = (object[])this.constructorArgs.ToArray(typeof(object)); - ConstructorInfo ci = this.type.GetConstructor(ReflectionUtils.GetTypes(caArray)); - if (ci == null && caArray.Length == 0) - { - ci = this.type.GetConstructors()[0]; - caArray = ReflectionUtils.GetDefaultValues(ReflectionUtils.GetParameterTypes(ci.GetParameters())); - } - - if (namedProperties.Count > 0) - { - PropertyInfo[] npArray = (PropertyInfo[])this.namedProperties.ToArray(typeof(PropertyInfo)); - object[] pvArray = (object[])this.propertyValues.ToArray(typeof(object)); - return new CustomAttributeBuilder(ci, caArray, npArray, pvArray); - } - else - { - return new CustomAttributeBuilder(ci, caArray); - } - - } - - #endregion - } - - #endregion - } +#endif + + #region Field Cache Management for "MemberwiseCopy" + + private const BindingFlags FIELDBINDINGS = + BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic; + + private static readonly Hashtable s_fieldCache = new Hashtable(); + + private static FieldInfo[] GetFields(Type type) + { + lock (s_fieldCache) + { + FieldInfo[] fields = (FieldInfo[])s_fieldCache[type]; + if (fields == null) + { + ArrayList fieldList = new ArrayList(); + CollectFieldsRecursive(type, fieldList); + fields = (FieldInfo[])fieldList.ToArray(typeof(FieldInfo)); + s_fieldCache[type] = fields; + } + return fields; + } + } + + private static void CollectFieldsRecursive(Type type, ArrayList fieldList) + { + if (type == typeof(object)) + return; + + FieldInfo[] fields = type.GetFields(FIELDBINDINGS); + fieldList.AddRange(fields); + CollectFieldsRecursive(type.BaseType, fieldList); + } + + #endregion Field Cache Management for "MemberwiseCopy" + + + #region CustomAttributeBuilderBuilder inner class definition + + /// + /// Creates a . + /// + /// Bruno Baia + public class CustomAttributeBuilderBuilder + { + #region Fields + + private Type type; + private ArrayList constructorArgs; + private ArrayList namedProperties; + private ArrayList propertyValues; + + #endregion + + #region Constructor(s) / Destructor + + /// + /// Creates a new instance of the + /// class. + /// + /// The custom attribute type. + public CustomAttributeBuilderBuilder(Type attributeType) + : + this(attributeType, ObjectUtils.EmptyObjects) + { + } + + /// + /// Creates a new instance of the + /// class. + /// + /// The custom attribute type. + /// The custom attribute constructor arguments. + public CustomAttributeBuilderBuilder(Type attributeType, params object[] constructorArgs) + { + AssertUtils.ArgumentNotNull(attributeType, "attributeType"); + if (!typeof(Attribute).IsAssignableFrom(attributeType)) + { + throw new ArgumentException( + string.Format("[{0}] does not derive from the [System.Attribute] class.", + attributeType.FullName)); + } + this.type = attributeType; + this.constructorArgs = new ArrayList(constructorArgs); + this.namedProperties = new ArrayList(); + this.propertyValues = new ArrayList(); + } + + #endregion + + #region Public Methods + + /// + /// Adds the specified values to the constructor argument list + /// used to create the custom attribute. + /// + /// An array of argument values. + public void AddContructorArgument(params object[] values) + { + this.constructorArgs.AddRange(values); + } + + /// + /// Adds a property value to the custom attribute. + /// + /// The property name. + /// The property value. + public void AddPropertyValue(string name, object value) + { + PropertyInfo propertyInfo = this.type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public); + if (propertyInfo == null) + { + throw new ArgumentException( + String.Format("The property '{0}' does no exist in the attribute '{1}'.", name, this.type)); + } + + this.namedProperties.Add(propertyInfo); + this.propertyValues.Add(value); + } + + /// + /// Creates the . + /// + /// The created . + public CustomAttributeBuilder Build() + { + object[] caArray = (object[])this.constructorArgs.ToArray(typeof(object)); + ConstructorInfo ci = this.type.GetConstructor(ReflectionUtils.GetTypes(caArray)); + if (ci == null && caArray.Length == 0) + { + ci = this.type.GetConstructors()[0]; + caArray = ReflectionUtils.GetDefaultValues(ReflectionUtils.GetParameterTypes(ci.GetParameters())); + } + + if (namedProperties.Count > 0) + { + PropertyInfo[] npArray = (PropertyInfo[])this.namedProperties.ToArray(typeof(PropertyInfo)); + object[] pvArray = (object[])this.propertyValues.ToArray(typeof(object)); + return new CustomAttributeBuilder(ci, caArray, npArray, pvArray); + } + else + { + return new CustomAttributeBuilder(ci, caArray); + } + + } + + #endregion + } + + #endregion + } } \ No newline at end of file diff --git a/src/Spring/Spring.Core/Util/SecurityCritical.cs b/src/Spring/Spring.Core/Util/SecurityCritical.cs new file mode 100644 index 00000000..152cad98 --- /dev/null +++ b/src/Spring/Spring.Core/Util/SecurityCritical.cs @@ -0,0 +1,50 @@ +#region License + +/* + * Copyright © 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#endregion + +using System.Runtime.CompilerServices; +using System.Security; + +namespace Spring.Util +{ + /// + /// Utility class to be used from within this assembly for executing security critical code + /// NEVER EVER MAKE THIS PUBLIC! + /// + /// Erich Eichinger + internal class SecurityCritical + { + internal delegate void PrivilegedCallback(); + + [SecurityCritical, SecurityTreatAsSafe] + [MethodImpl(MethodImplOptions.NoInlining)] + internal static void ExecutePrivileged(IStackWalk permission, PrivilegedCallback callback) + { + permission.Assert(); + try + { + callback(); + } + finally + { + CodeAccessPermission.RevertAssert(); + } + } + } +} diff --git a/src/Spring/Spring.Core/Util/SystemUtils.cs b/src/Spring/Spring.Core/Util/SystemUtils.cs index ddba4339..7546f0f8 100644 --- a/src/Spring/Spring.Core/Util/SystemUtils.cs +++ b/src/Spring/Spring.Core/Util/SystemUtils.cs @@ -21,10 +21,8 @@ #region Imports using System; -using System.Configuration; -using System.Reflection; +using System.Reflection; using System.Threading; -using System.Xml; #endregion diff --git a/src/Spring/Spring.Services/EnterpriseServices/EnterpriseServicesExporter.cs b/src/Spring/Spring.Services/EnterpriseServices/EnterpriseServicesExporter.cs index 82c39c37..6098e08e 100644 --- a/src/Spring/Spring.Services/EnterpriseServices/EnterpriseServicesExporter.cs +++ b/src/Spring/Spring.Services/EnterpriseServices/EnterpriseServicesExporter.cs @@ -233,7 +233,7 @@ namespace Spring.EnterpriseServices } /// - /// Use Spring context to configure the serviced components. + /// Use Spring context to configure the serviced components within COM. /// public bool UseSpring { diff --git a/src/Spring/Spring.Web/AssemblyInfo.cs b/src/Spring/Spring.Web/AssemblyInfo.cs index bf214506..b9a53b12 100644 --- a/src/Spring/Spring.Web/AssemblyInfo.cs +++ b/src/Spring/Spring.Web/AssemblyInfo.cs @@ -1,7 +1,24 @@ using System.Reflection; +using System.Security; using System.Web.UI; [assembly: AssemblyTitle("Spring.Web")] [assembly: AssemblyDescription("Interfaces and classes that provide web application support in Spring.Net")] [assembly: TagPrefix("Spring.Web.UI.Controls", "spring")] -//[assembly: AssemblyKeyFile(@"C:\users\aseovic\projects\OpenSource\Spring.Net\Spring.Net.PrivateKey.keys")] \ No newline at end of file +//[assembly: AssemblyKeyFile(@"C:\users\aseovic\projects\OpenSource\Spring.Net\Spring.Net.PrivateKey.keys")] +[assembly: AllowPartiallyTrustedCallers] +[assembly: SecurityCritical] + +#if NET_1_0 || NET_1_1 +namespace System.Security +{ + /// + /// + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Method)] + internal class SecurityCriticalAttribute : Attribute + { } + [AttributeUsage(AttributeTargets.Method)] + internal class SecurityTreatAsSafeAttribute : Attribute + { } +} +#endif diff --git a/src/Spring/Spring.Web/Context/Support/WebSupportModule.cs b/src/Spring/Spring.Web/Context/Support/WebSupportModule.cs index 11ebe2ea..c2667c2b 100644 --- a/src/Spring/Spring.Web/Context/Support/WebSupportModule.cs +++ b/src/Spring/Spring.Web/Context/Support/WebSupportModule.cs @@ -23,6 +23,8 @@ using System; using System.Globalization; using System.Reflection; +using System.Security; +using System.Security.Permissions; using System.Web; using System.Web.Caching; using System.Web.SessionState; @@ -80,8 +82,8 @@ namespace Spring.Context.Support private static CacheItemRemovedCallback s_originalCallback; #if NET_2_0 // required to enable accessing HttpContext.Request during IHttpModule.Init() in integrated mode - private static readonly FieldInfo fiHideRequestResponse = typeof(HttpContext).GetField("HideRequestResponse", BindingFlags.Instance|BindingFlags.NonPublic); - private static readonly SafeField ContextHideRequestResponse = (fiHideRequestResponse!=null)?new SafeField(fiHideRequestResponse):null; + private static readonly FieldInfo fiHideRequestResponse; + private static readonly SafeField ContextHideRequestResponse; #endif /// @@ -95,6 +97,20 @@ namespace Spring.Context.Support static WebSupportModule() { s_log = LogManager.GetLogger(typeof(WebSupportModule)); +#if NET_2_0 + // required to enable accessing HttpContext.Request during IHttpModule.Init() in integrated mode + ContextHideRequestResponse = null; + try + { + fiHideRequestResponse = typeof(HttpContext).GetField("HideRequestResponse", BindingFlags.Instance|BindingFlags.NonPublic); +// fiHideRequestResponse.SetValue(HttpContext.Current, false); + ContextHideRequestResponse = (fiHideRequestResponse!=null)?new SafeField(fiHideRequestResponse):null; + } + catch(SecurityException sec) + { + s_log.Warn(string.Format("failed reflecting field HttpContext.HideRequestResponse due to security restrictions {0}", sec)); + } +#endif // register additional resource handler ResourceHandlerRegistry.RegisterResourceHandler(WebUtils.DEFAULT_RESOURCE_PROTOCOL, typeof(WebResource)); diff --git a/src/Spring/Spring.Web/Spring.Web.2008.csproj b/src/Spring/Spring.Web/Spring.Web.2008.csproj index 8897b40b..4b0b17b7 100644 --- a/src/Spring/Spring.Web/Spring.Web.2008.csproj +++ b/src/Spring/Spring.Web/Spring.Web.2008.csproj @@ -23,6 +23,8 @@ v2.0 + true + ..\..\..\Spring.Net.snk ..\..\..\build\VS.Net.2008\Spring.Web\Debug\ @@ -124,6 +126,7 @@ Code + diff --git a/src/Spring/Spring.Web/Util/SecurityCritical.cs b/src/Spring/Spring.Web/Util/SecurityCritical.cs new file mode 100644 index 00000000..3248b7b0 --- /dev/null +++ b/src/Spring/Spring.Web/Util/SecurityCritical.cs @@ -0,0 +1,66 @@ +#region License + +/* + * Copyright © 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#endregion + +using System.Runtime.CompilerServices; +using System.Security; + +namespace Spring.Util +{ + /// + /// Utility class to be used from within this assembly for executing security critical code + /// NEVER EVER MAKE THIS PUBLIC! + /// + /// Erich Eichinger + internal class SecurityCritical + { + internal delegate void PrivilegedCallback(); + + [SecurityCritical, SecurityTreatAsSafe] + [MethodImpl(MethodImplOptions.NoInlining)] + internal static void ExecutePrivileged(IStackWalk permission, PrivilegedCallback callback) + { + permission.Assert(); + try + { + callback(); + } + finally + { + CodeAccessPermission.RevertAssert(); + } + } + + // internal delegate TResult PrivilegedCallback(); + // + // [SecurityCritical, SecurityTreatAsSafe] + // internal static TResult ExecutePrivileged(IStackWalk permission, PrivilegedCallback callback) + // { + // permission.Assert(); + // try + // { + // return callback(); + // } + // finally + // { + // CodeAccessPermission.RevertAssert(); + // } + // } + } +} diff --git a/src/Spring/Spring.Web/Web/Support/AbstractHandlerFactory.cs b/src/Spring/Spring.Web/Web/Support/AbstractHandlerFactory.cs index 9457e207..ed2c9eb8 100644 --- a/src/Spring/Spring.Web/Web/Support/AbstractHandlerFactory.cs +++ b/src/Spring/Spring.Web/Web/Support/AbstractHandlerFactory.cs @@ -23,6 +23,8 @@ using System; using System.Collections; using System.IO; +using System.Security; +using System.Security.Permissions; using System.Web; using System.Web.UI; using Common.Logging; @@ -94,7 +96,25 @@ namespace Spring.Web.Support /// /// Holds an instance of the instrinsic System.Web.UI.SimpleHandlerFactory /// - private static IHttpHandlerFactory s_simpleHandlerFactory; + private static readonly IHttpHandlerFactory s_simpleHandlerFactory; + + static AbstractHandlerFactory() + { + PrivilegedCommand cmd = new PrivilegedCommand(); + SecurityCritical.ExecutePrivileged(new PermissionSet(PermissionState.Unrestricted), new SecurityCritical.PrivilegedCallback(cmd.Execute)); + s_simpleHandlerFactory = cmd.Result; + } + + private class PrivilegedCommand + { + public IHttpHandlerFactory Result = null; + + public void Execute() + { + Type simpleHandlerFactoryType = typeof(IHttpHandler).Assembly.GetType("System.Web.UI.SimpleHandlerFactory"); + Result = (IHttpHandlerFactory)Activator.CreateInstance(simpleHandlerFactoryType, true); + } + } /// /// Get the global instance of System.Web.UI.SimpleHandlerFactory @@ -110,8 +130,6 @@ namespace Spring.Web.Support // instantiate lazy to avoid security exceptions in restricted reflection environments if (s_simpleHandlerFactory == null) { - Type simpleHandlerFactoryType = typeof(IHttpHandler).Assembly.GetType("System.Web.UI.SimpleHandlerFactory"); - s_simpleHandlerFactory = (IHttpHandlerFactory)Activator.CreateInstance(simpleHandlerFactoryType, true); } return s_simpleHandlerFactory; } @@ -128,7 +146,7 @@ namespace Spring.Web.Support /// protected AbstractHandlerFactory() { - this.Log = LogManager.GetLogger( this.GetType() ); + this.Log = LogManager.GetLogger(this.GetType()); } /// @@ -149,14 +167,14 @@ namespace Spring.Web.Support /// A new object that processes /// the request. /// - public virtual IHttpHandler GetHandler( HttpContext context, string requestType, string url, string physicalPath ) + public virtual IHttpHandler GetHandler(HttpContext context, string requestType, string url, string physicalPath) { bool isDebug = Log.IsDebugEnabled; #region Instrumentation if (isDebug) - Log.Debug( string.Format( "GetHandler():resolving url '{0}'", url ) ); + Log.Debug(string.Format("GetHandler():resolving url '{0}'", url)); #endregion @@ -172,7 +190,7 @@ namespace Spring.Web.Support if (isDebug) { - Log.Debug( string.Format( "GetHandler():resolved url '{0}' from reusable handler cache", url ) ); + Log.Debug(string.Format("GetHandler():resolved url '{0}' from reusable handler cache", url)); } #endregion @@ -187,7 +205,7 @@ namespace Spring.Web.Support { IConfigurableApplicationContext appContext = GetCheckedApplicationContext(url); - handler = CreateHandlerInstance( appContext, context, requestType, url, physicalPath ); + handler = CreateHandlerInstance(appContext, context, requestType, url, physicalPath); ApplyDependencyInjectionInfrastructure(handler, appContext); @@ -207,7 +225,7 @@ namespace Spring.Web.Support /// /// The object to release. /// - public virtual void ReleaseHandler( IHttpHandler handler ) + public virtual void ReleaseHandler(IHttpHandler handler) { } /// @@ -219,7 +237,7 @@ namespace Spring.Web.Support /// The requested . /// The physical path of the requested resource. /// A handler instance for processing the current request. - protected abstract IHttpHandler CreateHandlerInstance( IConfigurableApplicationContext appContext, HttpContext context, string requestType, string rawUrl, string physicalPath ); + protected abstract IHttpHandler CreateHandlerInstance(IConfigurableApplicationContext appContext, HttpContext context, string requestType, string rawUrl, string physicalPath); /// /// Get the application context instance corresponding to the given absolute url and checks @@ -236,16 +254,16 @@ namespace Spring.Web.Support /// /// Calls to obtain a context instance. /// - protected IConfigurableApplicationContext GetCheckedApplicationContext( string url ) + protected IConfigurableApplicationContext GetCheckedApplicationContext(string url) { - IApplicationContext appContext = GetContext( url ); + IApplicationContext appContext = GetContext(url); if (appContext == null) { - throw new ArgumentException( string.Format( "no application context for virtual path '{0}'", url ) ); + throw new ArgumentException(string.Format("no application context for virtual path '{0}'", url)); } if (!(appContext is IConfigurableApplicationContext)) { - throw new InvalidOperationException( string.Format( "application context '{0}' for virtual path '{1}' must implement IConfigurableApplicationContext", appContext.ToString(), url ) ); + throw new InvalidOperationException(string.Format("application context '{0}' for virtual path '{1}' must implement IConfigurableApplicationContext", appContext.ToString(), url)); } return (IConfigurableApplicationContext)appContext; } @@ -259,9 +277,9 @@ namespace Spring.Web.Support /// Subclasses may override this method to change the context source. /// By default, is used for obtaining context instances. /// - protected virtual IApplicationContext GetContext( string virtualPath ) + protected virtual IApplicationContext GetContext(string virtualPath) { - return WebApplicationContext.GetContext( virtualPath ); + return WebApplicationContext.GetContext(virtualPath); } /// @@ -276,27 +294,27 @@ namespace Spring.Web.Support /// /// Resolve an object definition by url. /// - protected internal static NamedObjectDefinition FindWebObjectDefinition( string appRelativeVirtualPath, IConfigurableListableObjectFactory objectFactory ) + protected internal static NamedObjectDefinition FindWebObjectDefinition(string appRelativeVirtualPath, IConfigurableListableObjectFactory objectFactory) { - ILog Log = LogManager.GetLogger( typeof( AbstractHandlerFactory ) ); + ILog Log = LogManager.GetLogger(typeof(AbstractHandlerFactory)); bool isDebug = Log.IsDebugEnabled; // lookup definition using app-relative url if (isDebug) - Log.Debug( string.Format( "GetHandler():looking up definition for app-relative url '{0}'", appRelativeVirtualPath ) ); + Log.Debug(string.Format("GetHandler():looking up definition for app-relative url '{0}'", appRelativeVirtualPath)); string objectDefinitionName = appRelativeVirtualPath; - IObjectDefinition pageDefinition = objectFactory.GetObjectDefinition( appRelativeVirtualPath, true ); + IObjectDefinition pageDefinition = objectFactory.GetObjectDefinition(appRelativeVirtualPath, true); if (pageDefinition == null) { // try using pagename+extension and pagename only - string pageExtension = Path.GetExtension( appRelativeVirtualPath ); - string pageName = WebUtils.GetPageName( appRelativeVirtualPath ); + string pageExtension = Path.GetExtension(appRelativeVirtualPath); + string pageName = WebUtils.GetPageName(appRelativeVirtualPath); // only looks in the specified object factory -- it will *not* search parent contexts - pageDefinition = objectFactory.GetObjectDefinition( pageName + pageExtension, false ); + pageDefinition = objectFactory.GetObjectDefinition(pageName + pageExtension, false); if (pageDefinition == null) { - pageDefinition = objectFactory.GetObjectDefinition( pageName, false ); + pageDefinition = objectFactory.GetObjectDefinition(pageName, false); if (pageDefinition != null) objectDefinitionName = pageName; } @@ -308,21 +326,21 @@ namespace Spring.Web.Support if (pageDefinition != null) { if (isDebug) - Log.Debug( string.Format( "GetHandler():found definition for page-name '{0}'", objectDefinitionName ) ); + Log.Debug(string.Format("GetHandler():found definition for page-name '{0}'", objectDefinitionName)); } else { if (isDebug) - Log.Debug( string.Format( "GetHandler():no definition found for page-name '{0}'", pageName ) ); + Log.Debug(string.Format("GetHandler():no definition found for page-name '{0}'", pageName)); } } else { if (isDebug) - Log.Debug( string.Format( "GetHandler():found definition for page-url '{0}'", appRelativeVirtualPath ) ); + Log.Debug(string.Format("GetHandler():found definition for page-url '{0}'", appRelativeVirtualPath)); } - return (pageDefinition == null) ? (NamedObjectDefinition)null : new NamedObjectDefinition( objectDefinitionName, pageDefinition ); + return (pageDefinition == null) ? (NamedObjectDefinition)null : new NamedObjectDefinition(objectDefinitionName, pageDefinition); } /// @@ -338,8 +356,8 @@ namespace Spring.Web.Support } else { - if ( (handler is ISupportsWebDependencyInjection) - && (((ISupportsWebDependencyInjection)handler).DefaultApplicationContext == null) ) + if ((handler is ISupportsWebDependencyInjection) + && (((ISupportsWebDependencyInjection)handler).DefaultApplicationContext == null)) { ((ISupportsWebDependencyInjection)handler).DefaultApplicationContext = applicationContext; } diff --git a/src/Spring/Spring.Web/Web/Support/ControlAccessor.cs b/src/Spring/Spring.Web/Web/Support/ControlAccessor.cs index 3635cd91..8a8e0f78 100644 --- a/src/Spring/Spring.Web/Web/Support/ControlAccessor.cs +++ b/src/Spring/Spring.Web/Web/Support/ControlAccessor.cs @@ -22,9 +22,11 @@ using System; using System.Diagnostics; using System.Reflection; using System.Reflection.Emit; +using System.Security; +using System.Security.Permissions; using System.Web.UI; using Spring.Reflection.Dynamic; -using Spring.Web.Support; +using Spring.Util; #endregion @@ -36,26 +38,20 @@ namespace Spring.Web.Support /// Erich Eichinger internal class ControlAccessor { - private static readonly MethodInfo s_miClear = GetMethod("Clear"); - private static MethodInfo GetMethod(string name) - { - return typeof(Control).GetMethod(name, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); - } - private static FieldInfo GetField(string name) - { - return typeof(Control).GetField(name, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); - } - private delegate ControlCollection CreateControlCollectionDelegate(Control target); private delegate void AddedControlDelegate(Control target, Control control, int index); private delegate void RemovedControlDelegate(Control target, Control control); private delegate void VoidMethodDelegate(Control target); + private static readonly MethodInfo s_miClear; + private static readonly SafeField ControlsArrayField; + #if NET_2_0 - private static readonly CreateControlCollectionDelegate BaseCreateControlCollection = (CreateControlCollectionDelegate) Delegate.CreateDelegate(typeof(CreateControlCollectionDelegate), GetMethod("CreateControlCollection")); - private static readonly AddedControlDelegate BaseAddedControl = (AddedControlDelegate) Delegate.CreateDelegate(typeof (AddedControlDelegate), GetMethod("AddedControl")); - private static readonly RemovedControlDelegate BaseRemovedControl = (RemovedControlDelegate) Delegate.CreateDelegate(typeof (RemovedControlDelegate), GetMethod("RemovedControl")); - private static readonly VoidMethodDelegate BaseClearNamingContainer = (VoidMethodDelegate) Delegate.CreateDelegate(typeof (VoidMethodDelegate), GetMethod("ClearNamingContainer")); + private static readonly CreateControlCollectionDelegate BaseCreateControlCollection; + private static readonly AddedControlDelegate BaseAddedControl; + private static readonly RemovedControlDelegate BaseRemovedControl; + private static readonly VoidMethodDelegate BaseClearNamingContainer; + #else private class DynamicMethodWrapper { @@ -117,6 +113,56 @@ namespace Spring.Web.Support private static readonly VoidMethodDelegate BaseClearNamingContainer = DynamicMethodWrapper.ClearNamingContainer(GetMethod("ClearNamingContainer")); #endif + static ControlAccessor() + { + SafeField fldControls = null; + MethodInfo fnClear = null; +#if NET_2_0 + SecurityCritical.ExecutePrivileged(new PermissionSet(PermissionState.Unrestricted), delegate + { +#endif + fnClear = GetMethod("Clear"); + fldControls = new SafeField(typeof(ControlCollection).GetField("_controls", BindingFlags.Instance | BindingFlags.NonPublic)); +#if NET_2_0 + }); +#endif + s_miClear = fnClear; + ControlsArrayField = fldControls; + +#if NET_2_0 + CreateControlCollectionDelegate fnBaseCreateControlCollection = null; + AddedControlDelegate fnBaseAddedControl = null; + RemovedControlDelegate fnBaseRemovedControl = null; + VoidMethodDelegate fnBaseClearNamingContainer = null; +#if NET_2_0 + SecurityCritical.ExecutePrivileged(new PermissionSet(PermissionState.Unrestricted), delegate + { +#endif + fnBaseCreateControlCollection = (CreateControlCollectionDelegate)Delegate.CreateDelegate(typeof(CreateControlCollectionDelegate), GetMethod("CreateControlCollection")); + fnBaseAddedControl = (AddedControlDelegate)Delegate.CreateDelegate(typeof(AddedControlDelegate), GetMethod("AddedControl")); + fnBaseRemovedControl = (RemovedControlDelegate)Delegate.CreateDelegate(typeof(RemovedControlDelegate), GetMethod("RemovedControl")); + fnBaseClearNamingContainer = (VoidMethodDelegate)Delegate.CreateDelegate(typeof(VoidMethodDelegate), GetMethod("ClearNamingContainer")); +#if NET_2_0 + }); +#endif + BaseCreateControlCollection = fnBaseCreateControlCollection; + BaseAddedControl = fnBaseAddedControl; + BaseRemovedControl = fnBaseRemovedControl; + BaseClearNamingContainer = fnBaseClearNamingContainer; +#endif + + } + + private static MethodInfo GetMethod(string name) + { + return typeof(Control).GetMethod(name, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); + } + private static FieldInfo GetField(string name) + { + return typeof(Control).GetField(name, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); + } + + private readonly Control _targetControl; /// @@ -187,7 +233,6 @@ namespace Spring.Web.Support } } - private static readonly SafeField ControlsArrayField = new SafeField(typeof(ControlCollection).GetField("_controls", BindingFlags.Instance|BindingFlags.NonPublic)); public void SetControlAt(Control control, int index) { Control[] controls = (Control[]) ControlsArrayField.GetValue(this.Controls); @@ -217,24 +262,29 @@ namespace Spring.Web.Support MethodInfo ensureOccasionalFields = GetMethod("EnsureOccasionalFields"); FieldInfo controls = occasionalFields.FieldType.GetField("Controls"); - System.Reflection.Emit.DynamicMethod dm = new System.Reflection.Emit.DynamicMethod("get_Controls", typeof(ControlCollection), new Type[] { typeof(Control) }, typeof(Control).Module, true); - ILGenerator il = dm.GetILGenerator(); - Label occFieldsNull = il.DefineLabel(); - Label retControls = il.DefineLabel(); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldfld, occasionalFields); - il.Emit(OpCodes.Brfalse_S, occFieldsNull); - il.MarkLabel(retControls); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldfld, occasionalFields); - il.Emit(OpCodes.Ldfld, controls); - il.Emit(OpCodes.Ret); - il.MarkLabel(occFieldsNull); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Call, ensureOccasionalFields); - il.Emit(OpCodes.Br, retControls); + GetControlsDelegate handler = null; - return (GetControlsDelegate) dm.CreateDelegate(typeof(GetControlsDelegate)); + SecurityCritical.ExecutePrivileged(new PermissionSet(PermissionState.Unrestricted), delegate + { + System.Reflection.Emit.DynamicMethod dm = new System.Reflection.Emit.DynamicMethod("get_Controls", typeof(ControlCollection), new Type[] { typeof(Control) }, typeof(Control).Module, true); + ILGenerator il = dm.GetILGenerator(); + Label occFieldsNull = il.DefineLabel(); + Label retControls = il.DefineLabel(); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldfld, occasionalFields); + il.Emit(OpCodes.Brfalse_S, occFieldsNull); + il.MarkLabel(retControls); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldfld, occasionalFields); + il.Emit(OpCodes.Ldfld, controls); + il.Emit(OpCodes.Ret); + il.MarkLabel(occFieldsNull); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Call, ensureOccasionalFields); + il.Emit(OpCodes.Br, retControls); + handler = (GetControlsDelegate) dm.CreateDelegate(typeof(GetControlsDelegate)); + }); + return handler; } private static SetControlsDelegate GetSetControlsDelegate() @@ -243,53 +293,30 @@ namespace Spring.Web.Support MethodInfo ensureOccasionalFields = GetMethod("EnsureOccasionalFields"); FieldInfo controls = occasionalFields.FieldType.GetField("Controls"); - System.Reflection.Emit.DynamicMethod dm = new System.Reflection.Emit.DynamicMethod("set_Controls", null, new Type[] { typeof(Control), typeof(ControlCollection) }, typeof(Control).Module, true); - ILGenerator il = dm.GetILGenerator(); - Label occFieldsNull = il.DefineLabel(); - Label setControls = il.DefineLabel(); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldfld, occasionalFields); - il.Emit(OpCodes.Brfalse_S, occFieldsNull); - il.MarkLabel(setControls); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldfld, occasionalFields); - il.Emit(OpCodes.Ldarg_1); - il.Emit(OpCodes.Stfld, controls); - il.Emit(OpCodes.Ret); - il.MarkLabel(occFieldsNull); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Call, ensureOccasionalFields); - il.Emit(OpCodes.Br, setControls); - - return (SetControlsDelegate) dm.CreateDelegate(typeof(SetControlsDelegate)); + SetControlsDelegate handler = null; + SecurityCritical.ExecutePrivileged(new PermissionSet(PermissionState.Unrestricted), delegate + { + System.Reflection.Emit.DynamicMethod dm = new System.Reflection.Emit.DynamicMethod("set_Controls", null, new Type[] { typeof(Control), typeof(ControlCollection) }, typeof(Control).Module, true); + ILGenerator il = dm.GetILGenerator(); + Label occFieldsNull = il.DefineLabel(); + Label setControls = il.DefineLabel(); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldfld, occasionalFields); + il.Emit(OpCodes.Brfalse_S, occFieldsNull); + il.MarkLabel(setControls); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldfld, occasionalFields); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Stfld, controls); + il.Emit(OpCodes.Ret); + il.MarkLabel(occFieldsNull); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Call, ensureOccasionalFields); + il.Emit(OpCodes.Br, setControls); + handler = (SetControlsDelegate) dm.CreateDelegate(typeof(SetControlsDelegate)); + }); + return handler; } - -// private static readonly Type s_tOccasionalFields = typeof(Control).GetNestedType("OccasionalFields", BindingFlags.NonPublic); -// -// private static readonly VoidMethodDelegate EnsureOccasionalFields = (VoidMethodDelegate) Delegate.CreateDelegate(typeof (VoidMethodDelegate), GetMethod("EnsureOccasionalFields")); -// private static readonly IDynamicField _occasionalFields = SafeField.CreateFrom(GetField("_occasionalFields")); -// private static readonly IDynamicField _controls = SafeField.CreateFrom(s_tOccasionalFields.GetField("Controls")); -// -// private ControlCollection GetChildControlCollection() -// { -// // we *must not* simply call control.Controls here! -// // Some controls (e.g. Repeater overload this property and call Control.EnsureChildControls() -// // which causes Control.ChildControlsCreated flag to be set and prevents children from being created after loading viewstate! -// -// EnsureOccasionalFields(_targetControl); -// -// object occasionalFields = _occasionalFields.GetValue(_targetControl); -// object childControls = _controls.GetValue(occasionalFields); -// return (ControlCollection) childControls; -// } -// -// private void SetChildControlCollection( ControlCollection controls ) -// { -// EnsureOccasionalFields(_targetControl); -// -// object occasionalFields = _occasionalFields.GetValue(_targetControl); -// _controls.SetValue(occasionalFields, controls); -// } #else private static readonly IDynamicField fControls = SafeField.CreateFrom(GetField("_controls")); diff --git a/src/Spring/Spring.Web/Web/Support/ControlCollectionAccessor.cs b/src/Spring/Spring.Web/Web/Support/ControlCollectionAccessor.cs index ab64582a..6ce037c1 100644 --- a/src/Spring/Spring.Web/Web/Support/ControlCollectionAccessor.cs +++ b/src/Spring/Spring.Web/Web/Support/ControlCollectionAccessor.cs @@ -20,8 +20,11 @@ using System; using System.Reflection; +using System.Security; +using System.Security.Permissions; using System.Web.UI; using Spring.Reflection.Dynamic; +using Spring.Util; #endregion @@ -33,12 +36,25 @@ namespace Spring.Web.Support /// Erich Eichinger internal class ControlCollectionAccessor { -#if MONO_2_0 - private static readonly IDynamicField _owner = new SafeField(typeof (ControlCollection).GetField("owner", BindingFlags.Instance | BindingFlags.NonPublic)); -#else - private static readonly IDynamicField _owner = new SafeField(typeof (ControlCollection).GetField("_owner", BindingFlags.Instance | BindingFlags.NonPublic)); + private static readonly IDynamicField _owner; + static ControlCollectionAccessor() + { + IDynamicField owner = null; +#if NET_2_0 + SecurityCritical.ExecutePrivileged( new PermissionSet(PermissionState.Unrestricted), delegate + { #endif - +#if MONO_2_0 + owner = new SafeField(typeof (ControlCollection).GetField("owner", BindingFlags.Instance | BindingFlags.NonPublic)); +#else + owner = new SafeField(typeof (ControlCollection).GetField("_owner", BindingFlags.Instance | BindingFlags.NonPublic)); +#endif +#if NET_2_0 + }); +#endif + _owner = owner; + } + private readonly ControlCollection _controls; private readonly Type _controlsType; diff --git a/src/Spring/Spring.Web/Web/Support/InterceptControlCollectionStrategy.cs b/src/Spring/Spring.Web/Web/Support/InterceptControlCollectionStrategy.cs index e285800b..326d3f9e 100644 --- a/src/Spring/Spring.Web/Web/Support/InterceptControlCollectionStrategy.cs +++ b/src/Spring/Spring.Web/Web/Support/InterceptControlCollectionStrategy.cs @@ -133,14 +133,13 @@ namespace Spring.Web.Support factoryMethod = (CreateControlCollectionDelegate)s_collectionFactoryCache[ownerType]; if (factoryMethod == null) { - Type interceptedCollectionType = - GetInterceptedCollectionType(collectionType, WebDependencyInjectionUtils.InjectDependenciesRecursive); + Type interceptedCollectionType = GetInterceptedCollectionType( + collectionType + , WebDependencyInjectionUtils.InjectDependenciesRecursive + ); - ConstructorInfo ctor = - interceptedCollectionType.GetConstructor(new Type[] { typeof(Control) }); - DynamicMethod dm = - new System.Reflection.Emit.DynamicMethod(string.Empty, typeof(ControlCollection), - new Type[] { typeof(Control) }); + ConstructorInfo ctor = interceptedCollectionType.GetConstructor(new Type[] { typeof(Control) }); + DynamicMethod dm = new DynamicMethod(string.Empty, typeof(ControlCollection), new Type[] { typeof(Control) }); ILGenerator il = dm.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Newobj, ctor); diff --git a/src/Spring/Spring.Web/Web/Support/LocalResourceManager.cs b/src/Spring/Spring.Web/Web/Support/LocalResourceManager.cs index fb74d81f..07f51361 100644 --- a/src/Spring/Spring.Web/Web/Support/LocalResourceManager.cs +++ b/src/Spring/Spring.Web/Web/Support/LocalResourceManager.cs @@ -24,6 +24,8 @@ using System; using System.Globalization; using System.Reflection; using System.Resources; +using System.Security; +using System.Security.Permissions; using System.Web; using System.Web.Compilation; using System.Web.UI; @@ -46,17 +48,33 @@ namespace Spring.Web.Support internal abstract class LocalResourceManager : ResourceManager { private delegate IResourceProvider GetResourceProviderDelegate( TemplateControl control ); - private static readonly GetResourceProviderDelegate getLocalResourceProvider = (GetResourceProviderDelegate)Delegate.CreateDelegate( typeof( GetResourceProviderDelegate ), typeof( ResourceExpressionBuilder ).GetMethod( "GetLocalResourceProvider", BindingFlags.Static | BindingFlags.NonPublic, null, new Type[] { typeof( TemplateControl ) }, null ) ); - private static readonly Type LocalResXResourceProviderFactoryType = typeof( IResourceProvider ).Assembly.GetType( "System.Web.Compilation.ResXResourceProviderFactory", true ); - private static readonly Type LocalResXResourceProviderType = typeof( IResourceProvider ).Assembly.GetType( "System.Web.Compilation.LocalResXResourceProvider", true ); - private static readonly ResourceProviderFactory LocalResXResourceProviderFactory = (ResourceProviderFactory)Activator.CreateInstance( LocalResXResourceProviderFactoryType, true ); - private static readonly SafeMethod fnGetLocalResourceAssembly = new SafeMethod( LocalResXResourceProviderType.GetMethod( "GetLocalResourceAssembly", BindingFlags.Instance | BindingFlags.NonPublic ) ); + private static readonly GetResourceProviderDelegate getLocalResourceProvider; + private static readonly Type LocalResXResourceProviderFactoryType; + private static readonly Type LocalResXResourceProviderType; + private static readonly ResourceProviderFactory LocalResXResourceProviderFactory; + private static readonly SafeMethod fnGetLocalResourceAssembly; /// /// Avoid beforeFieldInit /// static LocalResourceManager() - { } + { + LocalResXResourceProviderFactoryType = typeof(IResourceProvider).Assembly.GetType("System.Web.Compilation.ResXResourceProviderFactory", true); + LocalResXResourceProviderType = typeof(IResourceProvider).Assembly.GetType("System.Web.Compilation.LocalResXResourceProvider", true); + + GetResourceProviderDelegate fnGetResourceProvider = null; + ResourceProviderFactory rpf = null; + SafeMethod glra = null; + SecurityCritical.ExecutePrivileged(new PermissionSet(PermissionState.Unrestricted), delegate + { + fnGetResourceProvider = (GetResourceProviderDelegate)Delegate.CreateDelegate(typeof(GetResourceProviderDelegate), typeof(ResourceExpressionBuilder).GetMethod("GetLocalResourceProvider", BindingFlags.Static | BindingFlags.NonPublic, null, new Type[] { typeof(TemplateControl) }, null)); + rpf = (ResourceProviderFactory)Activator.CreateInstance( LocalResXResourceProviderFactoryType, true ); + glra = new SafeMethod(LocalResXResourceProviderType.GetMethod("GetLocalResourceAssembly", BindingFlags.Instance | BindingFlags.NonPublic)); + }); + getLocalResourceProvider = fnGetResourceProvider; + LocalResXResourceProviderFactory = rpf; + fnGetLocalResourceAssembly = glra; + } internal static ResourceManager GetLocalResourceManager( TemplateControl control ) { diff --git a/src/Spring/Spring.Web/Web/Support/PageHandlerFactory.cs b/src/Spring/Spring.Web/Web/Support/PageHandlerFactory.cs index 25ae6176..58146626 100644 --- a/src/Spring/Spring.Web/Web/Support/PageHandlerFactory.cs +++ b/src/Spring/Spring.Web/Web/Support/PageHandlerFactory.cs @@ -74,8 +74,6 @@ namespace Spring.Web.Support /// Instance of the IHttpHandler object that should be used to process request. public override IHttpHandler GetHandler(HttpContext context, string requestType, string url, string physicalPath) { - new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert(); - return base.GetHandler(context, requestType, url, physicalPath); } diff --git a/src/Spring/Spring.Web/Web/Support/SupportsWebDependencyInjectionOwnerProxy.cs b/src/Spring/Spring.Web/Web/Support/SupportsWebDependencyInjectionOwnerProxy.cs index 937215d1..083b436a 100644 --- a/src/Spring/Spring.Web/Web/Support/SupportsWebDependencyInjectionOwnerProxy.cs +++ b/src/Spring/Spring.Web/Web/Support/SupportsWebDependencyInjectionOwnerProxy.cs @@ -19,10 +19,13 @@ #region Imports using System.Reflection; +using System.Security; +using System.Security.Permissions; using System.Web.UI; using Spring.Context; using Spring.Context.Support; using Spring.Reflection.Dynamic; +using Spring.Util; using Spring.Web.Support; #endregion @@ -90,7 +93,17 @@ namespace Spring.Web.Support , INamingContainer { #if NET_2_0 - private static readonly SafeField refOccasionalFields = new SafeField(typeof(Control).GetField("_occasionalFields", BindingFlags.Instance|BindingFlags.NonPublic)); + private static readonly SafeField refOccasionalFields; + + static NamingContainerSupportsWebDependencyInjectionOwnerProxy() + { + SafeField fld = null; + SecurityCritical.ExecutePrivileged( new PermissionSet(PermissionState.Unrestricted), delegate + { + fld = new SafeField(typeof(Control).GetField("_occasionalFields", BindingFlags.Instance | BindingFlags.NonPublic)); + }); + refOccasionalFields = fld; + } #endif public NamingContainerSupportsWebDependencyInjectionOwnerProxy(IApplicationContext defaultApplicationContext, Control targetControl) : base(defaultApplicationContext, targetControl) diff --git a/src/Spring/Spring.Web/Web/UI/Controls/Panel.cs b/src/Spring/Spring.Web/Web/UI/Controls/Panel.cs index 0a52c5d9..fb037db5 100644 --- a/src/Spring/Spring.Web/Web/UI/Controls/Panel.cs +++ b/src/Spring/Spring.Web/Web/UI/Controls/Panel.cs @@ -174,6 +174,13 @@ namespace Spring.Web.UI.Controls } } + /// + /// Expose the context of this panel for medium trust safe access in e.g. . + /// + public new virtual HttpContext Context + { + get { return base.Context; } + } #region Dependency Injection Support private IApplicationContext _defaultApplicationContext; diff --git a/src/Spring/Spring.Web/Web/UI/Page.cs b/src/Spring/Spring.Web/Web/UI/Page.cs index a8fba0f6..8fcb7302 100644 --- a/src/Spring/Spring.Web/Web/UI/Page.cs +++ b/src/Spring/Spring.Web/Web/UI/Page.cs @@ -740,6 +740,8 @@ namespace Spring.Web.UI set { this.sharedState = value; } } + #endregion + #if NET_2_0 /// /// Overrides the default PreviousPage property to return an instance of , @@ -750,8 +752,16 @@ namespace Spring.Web.UI get { return this.Context.PreviousHandler as Page; } } #endif - - #endregion + /// + /// Publish associated with this page for convenient usage in Binding Expressions + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public new virtual HttpContext Context + { + get { + return base.Context; } + } #region Master Page support diff --git a/src/Spring/Spring.Web/Web/UI/UserControl.cs b/src/Spring/Spring.Web/Web/UI/UserControl.cs index 8108fc94..18823693 100644 --- a/src/Spring/Spring.Web/Web/UI/UserControl.cs +++ b/src/Spring/Spring.Web/Web/UI/UserControl.cs @@ -1110,6 +1110,19 @@ namespace Spring.Web.UI get { return (Page)base.Page; } } + /// + /// Publish associated with this page for convenient usage in Binding Expressions + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public new virtual HttpContext Context + { + get + { + return base.Context; + } + } + #endregion #region Helper Methods diff --git a/test/Spring/Spring.Core.Tests/Reflection/Dynamic/BasePropertyTests.cs b/test/Spring/Spring.Core.Tests/Reflection/Dynamic/BasePropertyTests.cs index 31238a25..a937c371 100644 --- a/test/Spring/Spring.Core.Tests/Reflection/Dynamic/BasePropertyTests.cs +++ b/test/Spring/Spring.Core.Tests/Reflection/Dynamic/BasePropertyTests.cs @@ -3,6 +3,7 @@ using System.CodeDom.Compiler; using System.Diagnostics; using System.IO; using System.Reflection; +using System.Runtime.CompilerServices; using System.Text; using NUnit.Framework; using Spring.Context.Support; @@ -264,14 +265,26 @@ namespace Spring.Reflection.Dynamic public class MyStaticClass { public const Int64 MyConst = 3456; - public static readonly string myReadonlyField = "hohoho"; + public static readonly string myReadonlyField; + private static readonly string myPrivateReadonlyField; public static string myField; + static MyStaticClass() + { + myReadonlyField = "hohoho"; + myPrivateReadonlyField = "hahaha"; + } + public static string MyProperty { get { return myField; } set { myField = value; } } + + public static string MyPrivateReadOnylFieldAccessor + { + get { return myPrivateReadonlyField; } + } } public struct MyStaticStruct diff --git a/test/Spring/Spring.Core.Tests/Reflection/Dynamic/DynamicFieldTests.cs b/test/Spring/Spring.Core.Tests/Reflection/Dynamic/DynamicFieldTests.cs index 9c0ebce3..503feb1e 100644 --- a/test/Spring/Spring.Core.Tests/Reflection/Dynamic/DynamicFieldTests.cs +++ b/test/Spring/Spring.Core.Tests/Reflection/Dynamic/DynamicFieldTests.cs @@ -23,6 +23,8 @@ using System; using System.Diagnostics; using System.Reflection; +using System.Security; +using System.Security.Permissions; using NUnit.Framework; using Spring.Context.Support; @@ -125,10 +127,54 @@ namespace Spring.Reflection.Dynamic catch (InvalidOperationException) { } IDynamicField myReadonlyField = Create( typeof( MyStaticClass ).GetField( "myReadonlyField" ) ); - Assert.AreEqual( "hohoho", myReadonlyField.GetValue( null ) ); + string s2 = (string) myReadonlyField.GetValue(null); + string s1 = MyStaticClass.myReadonlyField; + Assert.AreEqual(s1, s2); + } + + +#if NET_2_0 + + [Test] + public void CanReadPrivateReadOnlyField() + { + IDynamicField myPrivateReadonlyField2 = null; + FieldInfo fieldInfo = typeof(MyStaticClass).GetField("myPrivateReadonlyField", BindingFlags.Static | BindingFlags.NonPublic); + + myPrivateReadonlyField2 = Create(fieldInfo); + + string u2 = (string)myPrivateReadonlyField2.GetValue(null); + string u1 = "hahaha"; + Assert.AreEqual(u1, u2); + } + + [Test, Ignore("TODO: this works as expected when run using TD.NET & R# (in VS2k8), but fails with nant/NET 2.0 ?!?")] + public void CannotReadPrivateReadOnlyFieldIfNoReflectionPermission() + { + FieldInfo fieldInfo = typeof(MyStaticClass).GetField("myPrivateReadonlyField", BindingFlags.Static | BindingFlags.NonPublic); try { - myReadonlyField.SetValue( null, "some other string" ); + SecurityTemplate.MediumTrustInvoke( delegate + { + IDynamicField myPrivateReadonlyField2 = Create(fieldInfo); + }); + Assert.Fail("private field must not be accessible in medium trust: " + fieldInfo); + } + catch (SecurityException sex) + { + Assert.IsTrue( sex.Message.IndexOf("ReflectionPermission") > -1 ); + } + } +#endif + + [Test] + public void CannotSetStaticReadOnlyField() + { + IDynamicField myReadonlyField = Create(typeof(MyStaticClass).GetField("myReadonlyField")); + try + { + myReadonlyField.SetValue(null, "some other string"); + Assert.Fail(); } catch (InvalidOperationException) { } } diff --git a/test/Spring/Spring.Core.Tests/SecurityTemplate.cs b/test/Spring/Spring.Core.Tests/SecurityTemplate.cs new file mode 100644 index 00000000..2c170eb8 --- /dev/null +++ b/test/Spring/Spring.Core.Tests/SecurityTemplate.cs @@ -0,0 +1,526 @@ +#region License + +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#endregion + +#if NET_2_0 + +using System; +using System.Configuration; +using System.Data.SqlClient; +using System.Drawing.Printing; +using System.IO; +using System.Net; +//using System.Net.Mail; +using System.Runtime.InteropServices; +using System.Security; +using System.Security.Permissions; +using System.Security.Policy; +using System.Text; +using System.Threading; +using System.Web; +using System.Web.Configuration; + +namespace Spring +{ + /// + /// Allows to invoke parts of your code within the context of a certain PermissionSet. + /// + /// + /// + /// You may also use the static method and + /// to load a instance + /// yourself and apply it on your application domain using . Note, + /// that you must set the policy *before* an assembly gets loaded to apply that policy on that assembly! + /// + /// + /// The policy file format is the one used by . + /// You get good examples from your %FrameworkDir%/CONFIG/ directory (e.g. 'web_mediumtrust.config'). + /// + /// + /// Erich Eichinger + public class SecurityTemplate + { + /// + /// The default full trust permission set name ("FullTrust") + /// + public static readonly string PERMISSIONSET_FULLTRUST = "FullTrust"; + /// + /// The default no trust permission set name ("Nothing") + /// + public static readonly string PERMISSIONSET_NOTHING = "Nothing"; + /// + /// The default medium trust permission set name ("MediumTrust") + /// + public static readonly string PERMISSIONSET_MEDIUMTRUST = "MediumTrust"; + /// + /// The default low trust permission set name ("LowTrust") + /// + public static readonly string PERMISSIONSET_LOWTRUST = "LowTrust"; + /// + /// The default asp.net permission set name ("ASP.NET") + /// + public static readonly string PERMISSIONSET_ASPNET = "ASP.Net"; + + private readonly PolicyLevel _domainPolicy; + // private readonly Dictionary securityContextCache = new Dictionary(); + private bool throwOnUnknownPermissionSet = true; + + /// + /// Avoid beforeFieldInit + /// + static SecurityTemplate() + {} + + /// + /// Invoke the specified callback in a medium trusted context + /// + public static void MediumTrustInvoke( ThreadStart callback ) + { + SecurityTemplate template = new SecurityTemplate(false); + template.PartialTrustInvoke(PERMISSIONSET_MEDIUMTRUST, callback); + } + + /// + /// Access the domain of this instance. + /// + public PolicyLevel DomainPolicy + { + get { return _domainPolicy; } + } + + /// + /// Whether to throw an in case + /// the permission set name is not found when invoking . + /// Defaults to true. + /// + public bool ThrowOnUnknownPermissionSet + { + get { return throwOnUnknownPermissionSet; } + set + { + throwOnUnknownPermissionSet = value; + // securityContextCache.Clear(); // clear cache + } + } + + /// + /// Creates a new instance providing default "FullTrust", "Nothing", "MediumTrust" and "LowTrust" permissionsets + /// + /// NCover requires unmangaged code permissions, set this flag true in this case. + private SecurityTemplate(bool allowUnmanagedCode) + { + PolicyLevel pLevel = PolicyLevel.CreateAppDomainLevel(); + + // NOTHING permissionset + if (null == pLevel.GetNamedPermissionSet(PERMISSIONSET_NOTHING)) + { + NamedPermissionSet noPermissionSet = new NamedPermissionSet(PERMISSIONSET_NOTHING, PermissionState.None); + noPermissionSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.NoFlags)); + pLevel.AddNamedPermissionSet(noPermissionSet); + } + + // FULLTRUST permissionset + if (null == pLevel.GetNamedPermissionSet(PERMISSIONSET_FULLTRUST)) + { + NamedPermissionSet fulltrustPermissionSet = new NamedPermissionSet(PERMISSIONSET_FULLTRUST, PermissionState.Unrestricted); + pLevel.AddNamedPermissionSet(fulltrustPermissionSet); + } + // MEDIUMTRUST permissionset (corresponds to ASP.Net permission set in web_mediumtrust.config) + NamedPermissionSet mediumTrustPermissionSet = new NamedPermissionSet(PERMISSIONSET_MEDIUMTRUST, PermissionState.None); + mediumTrustPermissionSet.AddPermission(new AspNetHostingPermission(AspNetHostingPermissionLevel.Medium)); + mediumTrustPermissionSet.AddPermission(new DnsPermission(PermissionState.Unrestricted)); + mediumTrustPermissionSet.AddPermission(new EnvironmentPermission(EnvironmentPermissionAccess.Read, + "TEMP;TMP;USERNAME;OS;COMPUTERNAME")); + mediumTrustPermissionSet.AddPermission(new FileIOPermission(FileIOPermissionAccess.AllAccess, + AppDomain.CurrentDomain.BaseDirectory)); + IsolatedStorageFilePermission isolatedStorageFilePermission = new IsolatedStorageFilePermission(PermissionState.None); + isolatedStorageFilePermission.UsageAllowed = IsolatedStorageContainment.AssemblyIsolationByUser; + isolatedStorageFilePermission.UserQuota = 9223372036854775807; + mediumTrustPermissionSet.AddPermission(isolatedStorageFilePermission); + mediumTrustPermissionSet.AddPermission(new PrintingPermission(PrintingPermissionLevel.DefaultPrinting)); + SecurityPermissionFlag securityPermissionFlag = SecurityPermissionFlag.Assertion | SecurityPermissionFlag.Execution | + SecurityPermissionFlag.ControlThread | SecurityPermissionFlag.ControlPrincipal | + SecurityPermissionFlag.RemotingConfiguration; + if (allowUnmanagedCode) + { + securityPermissionFlag |= SecurityPermissionFlag.UnmanagedCode; + } + mediumTrustPermissionSet.AddPermission(new SecurityPermission(securityPermissionFlag)); +#if NET_2_0 + mediumTrustPermissionSet.AddPermission(new System.Net.Mail.SmtpPermission(System.Net.Mail.SmtpAccess.Connect)); +#endif + mediumTrustPermissionSet.AddPermission(new SqlClientPermission(PermissionState.Unrestricted)); + mediumTrustPermissionSet.AddPermission(new WebPermission()); + pLevel.AddNamedPermissionSet(mediumTrustPermissionSet); + + // LOWTRUST permissionset (corresponds to ASP.Net permission set in web_mediumtrust.config) + NamedPermissionSet lowTrustPermissionSet = new NamedPermissionSet(PERMISSIONSET_LOWTRUST, PermissionState.None); + lowTrustPermissionSet.AddPermission(new AspNetHostingPermission(AspNetHostingPermissionLevel.Low)); + lowTrustPermissionSet.AddPermission(new FileIOPermission(FileIOPermissionAccess.Read | FileIOPermissionAccess.PathDiscovery, + AppDomain.CurrentDomain.BaseDirectory)); + IsolatedStorageFilePermission isolatedStorageFilePermissionLow = new IsolatedStorageFilePermission(PermissionState.None); + isolatedStorageFilePermissionLow.UsageAllowed = IsolatedStorageContainment.AssemblyIsolationByUser; + isolatedStorageFilePermissionLow.UserQuota = 1048576; + lowTrustPermissionSet.AddPermission(isolatedStorageFilePermissionLow); + SecurityPermissionFlag securityPermissionFlagLow = SecurityPermissionFlag.Execution; + if (allowUnmanagedCode) + { + securityPermissionFlagLow |= SecurityPermissionFlag.UnmanagedCode; + } + lowTrustPermissionSet.AddPermission(new SecurityPermission(securityPermissionFlagLow)); + pLevel.AddNamedPermissionSet(lowTrustPermissionSet); + + // UnionCodeGroup rootCodeGroup = new UnionCodeGroup(new AllMembershipCondition(), new PolicyStatement(noPermissionSet, PolicyStatementAttribute.Nothing)); + // pLevel.RootCodeGroup = rootCodeGroup; + _domainPolicy = pLevel; + } + + /// + /// Loads domain policy from specified file + /// + /// + public SecurityTemplate(FileInfo securityConfigurationFile) + { + string appDirectory = AppDomain.CurrentDomain.BaseDirectory; + _domainPolicy = LoadDomainPolicyFromUri(new Uri(securityConfigurationFile.FullName), appDirectory, string.Empty); + } + + /// + /// Create a security tool from the specified domainPolicy + /// + public SecurityTemplate(PolicyLevel domainPolicy) + { + this._domainPolicy = domainPolicy; + } + + /// + /// Invokes the given callback using the policy's default + /// partial trust permissionset ("ASP.Net" ). + /// + public void PartialTrustInvoke(ThreadStart callback) + { + string defaultPermissionSetName = PERMISSIONSET_MEDIUMTRUST; + if (null != GetNamedPermissionSet(PERMISSIONSET_ASPNET)) + { + defaultPermissionSetName = PERMISSIONSET_ASPNET; + } + + PartialTrustInvoke(defaultPermissionSetName, callback); + } + + /// + /// Invokes the given callback using the specified permissionset. + /// +// [SecurityTreatAsSafe, SecurityCritical] + public void PartialTrustInvoke(string permissionSetName, ThreadStart callback) + { + PermissionSet ps = null; + ps = GetNamedPermissionSet(permissionSetName); + if (ps == null && throwOnUnknownPermissionSet) + { + throw new ArgumentOutOfRangeException("permissionSetName", permissionSetName, + string.Format("unknown PermissionSet name '{0}'", + permissionSetName)); + } + + if (!IsFullTrust(ps)) + { + ps.PermitOnly(); + callback(); + CodeAccessPermission.RevertPermitOnly(); + } + else + { + callback(); + } + } + + private PermissionSet GetNamedPermissionSet(string name) + { + if (_domainPolicy != null) + { + return _domainPolicy.GetNamedPermissionSet(name); + } + return null; + } + + /// + /// Loads the policy configuration from app.config configuration section + /// + /// + /// Configuration is identical to web.config: + /// + /// <configuration> + /// <system.web> + /// <securityPolicy> + /// <trustLevel name="Full" policyFile="internal"/> + /// <trustLevel name="High" policyFile="web_hightrust.config"/> + /// <trustLevel name="Medium" policyFile="web_mediumtrust.config"/> + /// <trustLevel name="Low" policyFile="web_lowtrust.config"/> + /// <trustLevel name="Minimal" policyFile="web_minimaltrust.config"/> + /// </securityPolicy> + /// <trust level="Medium" originUrl=""/> + /// </system.web> + /// </configuration> + /// + /// + /// + /// + public static PolicyLevel LoadDomainPolicyFromAppConfig(bool throwOnError) + { + TrustSection trustSection = (TrustSection)ConfigurationManager.GetSection("system.web/trust"); + SecurityPolicySection securityPolicySection = (SecurityPolicySection)ConfigurationManager.GetSection("system.web/securityPolicy"); + + if ((trustSection == null) || string.IsNullOrEmpty(trustSection.Level)) + { + if (!throwOnError) + return null; + throw new ConfigurationErrorsException("Configuration section not found "); + } + + if (trustSection.Level == "Full") + { + return null; + } + + if ((securityPolicySection == null) || (securityPolicySection.TrustLevels[trustSection.Level] == null)) + { + if (!throwOnError) + return null; + throw new ConfigurationErrorsException(string.Format("configuration not found", trustSection.Level)); + } + + string policyFileExpanded = GetPolicyFilenameExpanded(securityPolicySection.TrustLevels[trustSection.Level]); + string appDirectory = AppDomain.CurrentDomain.BaseDirectory; + PolicyLevel domainPolicy = LoadDomainPolicyFromUri(new Uri(policyFileExpanded), appDirectory, trustSection.OriginUrl); + return domainPolicy; + } + + /// + /// Loads a policy from a file (), + /// replacing placeholders + /// + /// $AppDir$, $AppDirUrl$ => + /// $CodeGen$ => (TODO) + /// $OriginHost$ => + /// $Gac$ => the current machine's GAC path + /// + /// + /// + /// + /// + /// + public static PolicyLevel LoadDomainPolicyFromUri(Uri policyFileLocation, string appDirectory, string originUrl) + { + bool foundGacToken = false; + PolicyLevel domainPolicy = CreatePolicyLevel(policyFileLocation, appDirectory, appDirectory, originUrl, out foundGacToken); + if (foundGacToken) + { + CodeGroup rootCodeGroup = domainPolicy.RootCodeGroup; + bool hasGacMembershipCondition = false; + foreach (CodeGroup childCodeGroup in rootCodeGroup.Children) + { + if (childCodeGroup.MembershipCondition is GacMembershipCondition) + { + hasGacMembershipCondition = true; + break; + } + } + if (!hasGacMembershipCondition && (rootCodeGroup is FirstMatchCodeGroup)) + { + FirstMatchCodeGroup firstMatchCodeGroup = (FirstMatchCodeGroup)rootCodeGroup; + if ((firstMatchCodeGroup.MembershipCondition is AllMembershipCondition) && (firstMatchCodeGroup.PermissionSetName == PERMISSIONSET_NOTHING)) + { + PermissionSet unrestrictedPermissionSet = new PermissionSet(PermissionState.Unrestricted); + CodeGroup gacGroup = new UnionCodeGroup(new GacMembershipCondition(), new PolicyStatement(unrestrictedPermissionSet)); + CodeGroup rootGroup = new FirstMatchCodeGroup(rootCodeGroup.MembershipCondition, rootCodeGroup.PolicyStatement); + foreach (CodeGroup childGroup in rootCodeGroup.Children) + { + if (((childGroup is UnionCodeGroup) && (childGroup.MembershipCondition is UrlMembershipCondition)) && (childGroup.PolicyStatement.PermissionSet.IsUnrestricted() && (gacGroup != null))) + { + rootGroup.AddChild(gacGroup); + gacGroup = null; + } + rootGroup.AddChild(childGroup); + } + domainPolicy.RootCodeGroup = rootGroup; + } + } + } + return domainPolicy; + } + + private static PolicyLevel CreatePolicyLevel(Uri configFile, string appDir, string binDir, string strOriginUrl, out bool foundGacToken) + { + WebClient webClient = new WebClient(); + string strXmlPolicy = webClient.DownloadString(configFile); + appDir = FileUtil.RemoveTrailingDirectoryBackSlash(appDir); + binDir = FileUtil.RemoveTrailingDirectoryBackSlash(binDir); + strXmlPolicy = strXmlPolicy.Replace("$AppDir$", appDir).Replace("$AppDirUrl$", MakeFileUrl(appDir)).Replace("$CodeGen$", MakeFileUrl(binDir)); + if (strOriginUrl == null) + { + strOriginUrl = string.Empty; + } + strXmlPolicy = strXmlPolicy.Replace("$OriginHost$", strOriginUrl); + if (strXmlPolicy.IndexOf("$Gac$", StringComparison.Ordinal) != -1) + { + string gacLocation = GetGacLocation(); + if (gacLocation != null) + { + gacLocation = MakeFileUrl(gacLocation); + } + if (gacLocation == null) + { + gacLocation = string.Empty; + } + strXmlPolicy = strXmlPolicy.Replace("$Gac$", gacLocation); + foundGacToken = true; + } + else + { + foundGacToken = false; + } + return SecurityManager.LoadPolicyLevelFromString(strXmlPolicy, PolicyLevelType.AppDomain); + } + + private static string GetPolicyFilenameExpanded(TrustLevel trustLevel) + { + bool isRelative = true; + if (trustLevel.PolicyFile.Length > 1) + { + char ch = trustLevel.PolicyFile[1]; + char ch2 = trustLevel.PolicyFile[0]; + if (ch == ':') + { + isRelative = false; + } + else if ((ch2 == '\\') && (ch == '\\')) + { + isRelative = false; + } + } + + if (isRelative) + { + string configurationElementFileSource = trustLevel.ElementInformation.Properties["policyFile"].Source; + string path = configurationElementFileSource.Substring(0, configurationElementFileSource.LastIndexOf('\\') + 1); + return path + trustLevel.PolicyFile; + } + return trustLevel.PolicyFile; + } + + [DllImport("mscorwks.dll", CharSet = CharSet.Unicode)] + private static extern int GetCachePath(int dwCacheFlags, StringBuilder pwzCachePath, ref int pcchPath); + + private static string GetGacLocation() + { + int capacity = 0x106; + StringBuilder pwzCachePath = new StringBuilder(capacity); + int pcchPath = capacity - 2; + int hRes = GetCachePath(2, pwzCachePath, ref pcchPath); + if (hRes < 0) + { + throw new HttpException("failed obtaining GAC path", hRes); + } + return pwzCachePath.ToString(); + } + + private static string MakeFileUrl(string path) + { + Uri uri = new Uri(path); + return uri.ToString(); + } + + private class FileUtil + { + internal static string RemoveTrailingDirectoryBackSlash(string path) + { + if (path == null) + { + return null; + } + int length = path.Length; + if ((length > 3) && (path[length - 1] == '\\')) + { + path = path.Substring(0, length - 1); + } + return path; + } + } + + private static bool IsFullTrust(PermissionSet perms) + { + if (perms != null) + { + return perms.IsUnrestricted(); + } + return true; + } + + // [SecurityTreatAsSafe, SecurityCritical] + // private bool NeedPartialTrustInvoke(string permissionSetName) + // { + // if (_domainPolicy == null) return false; + // + // SecurityContext securityContext = null; + // if (!securityContextCache.ContainsKey(permissionSetName)) + // { + // NamedPermissionSet permissionSet = _domainPolicy.GetNamedPermissionSet(permissionSetName); + // if (permissionSet == null && throwOnUnknownPermissionSet) + // { + // throw new ArgumentOutOfRangeException("permissionSetName", permissionSetName, "Undefined permission set"); + // } + // if (!IsFullTrust(permissionSet)) + // { + // try + // { + // permissionSet.PermitOnly(); + // securityContext = CaptureSecurityContextNoIdentityFlow(); + // } + // finally + // { + // CodeAccessPermission.RevertPermitOnly(); + // } + // } + // securityContextCache[permissionSetName] = securityContext; + // } + // else + // { + // securityContext = securityContextCache[permissionSetName]; + // } + // return (securityContext != null); + // } + + + // [SecurityCritical] + // private static SecurityContext CaptureSecurityContextNoIdentityFlow() + // { + // if (SecurityContext.IsWindowsIdentityFlowSuppressed()) + // { + // return SecurityContext.Capture(); + // } + // using (SecurityContext.SuppressFlowWindowsIdentity()) + // { + // return SecurityContext.Capture(); + // } + // } + } +} + +#endif \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Spring.Core.Tests.2008.csproj b/test/Spring/Spring.Core.Tests/Spring.Core.Tests.2008.csproj index 77754094..a0ce0057 100644 --- a/test/Spring/Spring.Core.Tests/Spring.Core.Tests.2008.csproj +++ b/test/Spring/Spring.Core.Tests/Spring.Core.Tests.2008.csproj @@ -656,6 +656,7 @@ + Code diff --git a/test/Spring/Spring.Core.Tests/Util/ReflectionUtilsMemberwiseCopyTests.cs b/test/Spring/Spring.Core.Tests/Util/ReflectionUtilsMemberwiseCopyTests.cs index ca7eb606..76d9bec1 100644 --- a/test/Spring/Spring.Core.Tests/Util/ReflectionUtilsMemberwiseCopyTests.cs +++ b/test/Spring/Spring.Core.Tests/Util/ReflectionUtilsMemberwiseCopyTests.cs @@ -1,4 +1,8 @@ using System; +using System.Security; +using System.Security.Permissions; +using System.Threading; +using System.Web; using NUnit.Framework; namespace Spring.Util @@ -46,9 +50,50 @@ namespace Spring.Util ReflectionUtils.MemberwiseCopy(i2, i1); - Assert.AreEqual(i2, i1); + Assert.AreEqual(i1, i2); } - } + +#if NET_2_0 + [Test] + public void MediumTrustAllowsCopyingBetweenTypesFromSameModule() + { + SampleBaseClass i1 = new SampleDerivedClass("1st config val"); + SampleBaseClass i2 = new SampleFurtherDerivedClass("2nd config val"); + + SecurityTemplate.MediumTrustInvoke(new ThreadStart(new CopyCommand(i2, i1).Execute)); + Assert.AreEqual(i1, i2); + } + + [Test] + public void MediumTrustThrowsSecurityExceptionWhenCopyingBetweenTypesFromDifferentModules() + { + Exception e1 = new Exception("my name is e1"); + HttpException e2 = new HttpException("my name is e2"); + // I know, I am a bit paranoid about that basic assumption + Assert.AreNotEqual( e1.GetType().Assembly, e2.GetType().Assembly ); + + SecurityTemplate.MediumTrustInvoke(new ThreadStart(new CopyCommand(e2, e1).Execute)); + Assert.AreEqual(e1.Message, e2.Message); + } + + class CopyCommand + { + private object a; + private object b; + + public CopyCommand(object a, object b) + { + this.a = a; + this.b = b; + } + + public void Execute() + { + ReflectionUtils.MemberwiseCopy(a, b); + } + } +#endif + } #region Test Support Classes @@ -57,7 +102,7 @@ namespace Spring.Util private const string MyConstant = "SampleBaseClass.MyConstant"; private readonly string _someReadOnlyVal = "SampleBaseClass.SomeReadOnlyVal"; protected readonly string _someProtectedReadOnlyVal = "SampleBaseClass.SomeProtectedReadOnlyVal"; - private string _someConfigVal = "SampleBaseClass.SomeConfigVal"; + private string _someConfigVal; public SampleBaseClass(string someConfigVal) { @@ -76,9 +121,12 @@ namespace Spring.Util public override bool Equals(object obj) { - if (this == obj) return true; - SampleBaseClass sampleBaseClass = obj as SampleBaseClass; - if (sampleBaseClass == null) return false; + if (ReferenceEquals(obj, null) || (!this.GetType().IsAssignableFrom(obj.GetType()))) + return false; + if (ReferenceEquals(this , obj)) + return true; + + SampleBaseClass sampleBaseClass = (SampleBaseClass) obj; if (!Equals(_someReadOnlyVal, sampleBaseClass._someReadOnlyVal)) return false; if (!Equals(_someProtectedReadOnlyVal, sampleBaseClass._someProtectedReadOnlyVal)) return false; if (!Equals(_someConfigVal, sampleBaseClass._someConfigVal)) return false; @@ -102,11 +150,12 @@ namespace Spring.Util public override bool Equals(object obj) { - if (this == obj) return true; - SampleDerivedClass sampleDerivedClass = obj as SampleDerivedClass; - if (sampleDerivedClass == null) return false; - if (!base.Equals(obj)) return false; - if (!Equals(_someConfigVal, sampleDerivedClass._someConfigVal)) return false; + if (!base.Equals(obj)) + return false; + + SampleDerivedClass sampleDerivedClass = (SampleDerivedClass)obj; + if (!Equals(_someConfigVal, sampleDerivedClass._someConfigVal)) + return false; return true; } }