changeset 83:7e9ffde4022d

Implementando DataAnnotation desde recursos y por convención
author nelopauselli
date Tue, 24 May 2011 21:37:06 -0300
parents c8897b1c6f49
children ee4e699e4551
files Agendas/trunk/src/Agendas.Resources/Agendas.Resources.csproj Agendas/trunk/src/Agendas.Resources/Properties/AssemblyInfo.cs Agendas/trunk/src/Agendas.Resources/Properties/DataAnnotationResources.Designer.cs Agendas/trunk/src/Agendas.Resources/Properties/DataAnnotationResources.resx Agendas/trunk/src/Agendas.Web/Agendas.Web.csproj Agendas/trunk/src/Agendas.Web/Global.asax.cs Agendas/trunk/src/Agendas.Web/ModelMetadataWithDefaultsProvider.asax.cs Agendas/trunk/src/Agendas.Web/Models/EventoModel.cs Agendas/trunk/src/Agendas.Web/Models/PropuestaModel.cs Agendas/trunk/src/Agendas.sln
diffstat 10 files changed, 511 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Resources/Agendas.Resources.csproj	Tue May 24 21:37:06 2011 -0300
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>8.0.30703</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{444D25FB-FC1C-48DC-9EAD-D4C78F2A10CA}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>AltNetHispano.Agendas.Resources</RootNamespace>
+    <AssemblyName>AltNetHispano.Agendas.Resources</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Properties\DataAnnotationResources.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DesignTime>True</DesignTime>
+      <DependentUpon>DataAnnotationResources.resx</DependentUpon>
+    </Compile>
+  </ItemGroup>
+  <ItemGroup>
+    <EmbeddedResource Include="Properties\DataAnnotationResources.resx">
+      <Generator>PublicResXFileCodeGenerator</Generator>
+      <LastGenOutput>DataAnnotationResources.Designer.cs</LastGenOutput>
+    </EmbeddedResource>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Resources/Properties/AssemblyInfo.cs	Tue May 24 21:37:06 2011 -0300
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Agendas.Resources")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Microsoft")]
+[assembly: AssemblyProduct("Agendas.Resources")]
+[assembly: AssemblyCopyright("Copyright © Microsoft 2011")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("f1f30a73-9935-4d8f-9a40-6a1fdcb9ff95")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Resources/Properties/DataAnnotationResources.Designer.cs	Tue May 24 21:37:06 2011 -0300
@@ -0,0 +1,126 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//     Runtime Version:4.0.30319.225
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace AltNetHispano.Agendas.Resources.Properties {
+    using System;
+    
+    
+    /// <summary>
+    ///   A strongly-typed resource class, for looking up localized strings, etc.
+    /// </summary>
+    // This class was auto-generated by the StronglyTypedResourceBuilder
+    // class via a tool like ResGen or Visual Studio.
+    // To add or remove a member, edit your .ResX file then rerun ResGen
+    // with the /str option, or rebuild your VS project.
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    public class DataAnnotationResources {
+        
+        private static global::System.Resources.ResourceManager resourceMan;
+        
+        private static global::System.Globalization.CultureInfo resourceCulture;
+        
+        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+        internal DataAnnotationResources() {
+        }
+        
+        /// <summary>
+        ///   Returns the cached ResourceManager instance used by this class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        public static global::System.Resources.ResourceManager ResourceManager {
+            get {
+                if (object.ReferenceEquals(resourceMan, null)) {
+                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("AltNetHispano.Agendas.Resources.Properties.DataAnnotationResources", typeof(DataAnnotationResources).Assembly);
+                    resourceMan = temp;
+                }
+                return resourceMan;
+            }
+        }
+        
+        /// <summary>
+        ///   Overrides the current thread's CurrentUICulture property for all
+        ///   resource lookups using this strongly typed resource class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        public static global::System.Globalization.CultureInfo Culture {
+            get {
+                return resourceCulture;
+            }
+            set {
+                resourceCulture = value;
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to debe ingresar la fecha del evento.
+        /// </summary>
+        public static string FechaRequired {
+            get {
+                return ResourceManager.GetString("FechaRequired", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to debe ingresar el nombre del ponente.
+        /// </summary>
+        public static string PonenteRequired {
+            get {
+                return ResourceManager.GetString("PonenteRequired", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Título.
+        /// </summary>
+        public static string Titulo {
+            get {
+                return ResourceManager.GetString("Titulo", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Título del evento, el mismo lo identifica entre todos los eventos.
+        /// </summary>
+        public static string TituloDescription {
+            get {
+                return ResourceManager.GetString("TituloDescription", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to debe ingresar el título.
+        /// </summary>
+        public static string TituloRequired {
+            get {
+                return ResourceManager.GetString("TituloRequired", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Url de la invitación.
+        /// </summary>
+        public static string UrlInvitacion {
+            get {
+                return ResourceManager.GetString("UrlInvitacion", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to la url ingresada no es válida.
+        /// </summary>
+        public static string UrlInvitacionUrl {
+            get {
+                return ResourceManager.GetString("UrlInvitacionUrl", resourceCulture);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Resources/Properties/DataAnnotationResources.resx	Tue May 24 21:37:06 2011 -0300
@@ -0,0 +1,141 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <data name="FechaRequired" xml:space="preserve">
+    <value>debe ingresar la fecha del evento</value>
+  </data>
+  <data name="PonenteRequired" xml:space="preserve">
+    <value>debe ingresar el nombre del ponente</value>
+  </data>
+  <data name="Titulo" xml:space="preserve">
+    <value>Título</value>
+  </data>
+  <data name="TituloDescription" xml:space="preserve">
+    <value>Título del evento, el mismo lo identifica entre todos los eventos</value>
+  </data>
+  <data name="TituloRequired" xml:space="preserve">
+    <value>debe ingresar el título</value>
+  </data>
+  <data name="UrlInvitacion" xml:space="preserve">
+    <value>Url de la invitación</value>
+  </data>
+  <data name="UrlInvitacionUrl" xml:space="preserve">
+    <value>la url ingresada no es válida</value>
+  </data>
+</root>
\ No newline at end of file
--- a/Agendas/trunk/src/Agendas.Web/Agendas.Web.csproj	Tue May 24 19:31:10 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Web/Agendas.Web.csproj	Tue May 24 21:37:06 2011 -0300
@@ -69,6 +69,7 @@
       <DependentUpon>Global.asax</DependentUpon>
     </Compile>
     <Compile Include="HttpContextIdentityProvider.cs" />
+    <Compile Include="ModelMetadataWithDefaultsProvider.asax.cs" />
     <Compile Include="Models\AccountModels.cs" />
     <Compile Include="Models\EventoModel.cs" />
     <Compile Include="Models\PropuestaModel.cs" />
@@ -156,6 +157,10 @@
       <Project>{306DDA8A-49A5-42E5-A639-A9D3D521865F}</Project>
       <Name>Agendas.Factories</Name>
     </ProjectReference>
+    <ProjectReference Include="..\Agendas.Resources\Agendas.Resources.csproj">
+      <Project>{444D25FB-FC1C-48DC-9EAD-D4C78F2A10CA}</Project>
+      <Name>Agendas.Resources</Name>
+    </ProjectReference>
   </ItemGroup>
   <ItemGroup>
     <Content Include="Views\Shared\_Menu.cshtml" />
--- a/Agendas/trunk/src/Agendas.Web/Global.asax.cs	Tue May 24 19:31:10 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Web/Global.asax.cs	Tue May 24 21:37:06 2011 -0300
@@ -2,6 +2,7 @@
 using System.Web.Routing;
 using AltNetHispano.Agendas.Domain;
 using AltNetHispano.Agendas.Factories;
+using AltNetHispano.Agendas.Resources.Properties;
 
 namespace AltNetHispano.Agendas.Web
 {
@@ -30,6 +31,8 @@
 
         protected void Application_Start()
         {
+			ModelMetadataProviders.Current = new ModelMetadataWithDefaultsProvider(new ModelMetadataLocalizable<DataAnnotationResources>());
+
             AreaRegistration.RegisterAllAreas();
 
             RegisterGlobalFilters(GlobalFilters.Filters);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Web/ModelMetadataWithDefaultsProvider.asax.cs	Tue May 24 21:37:06 2011 -0300
@@ -0,0 +1,121 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Web.Mvc;
+
+namespace AltNetHispano.Agendas.Web
+{
+	public class ModelMetadataWithDefaultsProvider : ModelMetadataProvider
+	{
+		private readonly DataAnnotationsModelMetadataProvider _base;
+
+		public ModelMetadataWithDefaultsProvider(IModelMetadataResolver modelMetadataResolver)
+		{
+			_base = new DataAnnotationsModelMetadataProviderWithAttributes(modelMetadataResolver);
+		}
+
+		public override IEnumerable<ModelMetadata> GetMetadataForProperties(object container, Type containerType)
+		{
+			return _base.GetMetadataForProperties(container, containerType);
+		}
+
+		public override ModelMetadata GetMetadataForProperty(Func<object> modelAccessor, Type containerType, string propertyName)
+		{
+			var modelMetadata = _base.GetMetadataForProperty(modelAccessor, containerType, propertyName);
+			return modelMetadata;
+		}
+
+		public override ModelMetadata GetMetadataForType(Func<object> modelAccessor, Type modelType)
+		{
+			return _base.GetMetadataForType(modelAccessor, modelType);
+		}
+	}
+
+	public class DataAnnotationsModelMetadataProviderWithAttributes : DataAnnotationsModelMetadataProvider
+	{
+		private readonly IModelMetadataResolver _modelMetadataResolver;
+		private List<Attribute> _attributeList;
+
+		public DataAnnotationsModelMetadataProviderWithAttributes(IModelMetadataResolver modelMetadataResolver)
+		{
+			_modelMetadataResolver = modelMetadataResolver;
+		}
+
+		protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
+		{
+			_attributeList = new List<Attribute>(attributes);
+
+			var modelMetadata = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
+
+			if (propertyName != null)
+			{
+				if (string.IsNullOrWhiteSpace(modelMetadata.DisplayName))
+					modelMetadata.DisplayName = _modelMetadataResolver.GetDisplayName(propertyName);
+
+				if (string.IsNullOrWhiteSpace(modelMetadata.Description))
+					modelMetadata.Description = _modelMetadataResolver.GetDescription(propertyName);
+
+				var validators = _attributeList.OfType<ValidationAttribute>();
+				foreach (var validator in validators)
+				{
+					if (string.IsNullOrWhiteSpace(validator.ErrorMessage) &&
+						string.IsNullOrWhiteSpace(validator.ErrorMessageResourceName))
+					{
+						var resourceName = propertyName + validator.GetType().Name;
+						if (resourceName.EndsWith("Attribute"))
+							resourceName = resourceName.Substring(0, resourceName.Length - 9);
+						var resourceType = validator.ErrorMessageResourceType ?? _modelMetadataResolver.ResourceType;
+						var prop = resourceType.GetProperty(resourceName);
+						if (prop != null)
+						{
+							validator.ErrorMessageResourceType = resourceType;
+							validator.ErrorMessageResourceName = resourceName;
+						}
+					}
+				}
+			}
+
+			return modelMetadata;
+		}
+	}
+
+	public interface IModelMetadataResolver
+	{
+		string GetDisplayName(string propertyName);
+		string GetDescription(string propertyName);
+		Type ResourceType { get; }
+	}
+
+	public class ModelMetadataLocalizable<T> : IModelMetadataResolver
+	{
+		public string GetDisplayName(string propertyName)
+		{
+			return SearchResource(propertyName);
+		}
+
+		public string GetDescription(string propertyName)
+		{
+			return SearchResource(propertyName + "Description");
+		}
+
+		public Type ResourceType
+		{
+			get { return typeof(T); }
+		}
+
+		private static string SearchResource(string resourceName)
+		{
+			string displayName = null;
+			var resourceType = typeof(T);
+			var prop = resourceType.GetProperty(resourceName);
+			if (prop != null)
+			{
+				var value = prop.GetValue(resourceType, null);
+				displayName = value != null ? value.ToString() : resourceName;
+			}
+			return displayName;
+		}
+
+	}
+}
\ No newline at end of file
--- a/Agendas/trunk/src/Agendas.Web/Models/EventoModel.cs	Tue May 24 19:31:10 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Web/Models/EventoModel.cs	Tue May 24 21:37:06 2011 -0300
@@ -13,13 +13,13 @@
 
     public class EventoNewModel
     {
-        [Required(ErrorMessage = "debe ingresar el título")]
+        [Required]
         public string Titulo { get; set; }
 
-        [Required(ErrorMessage = "debe ingresar el nombre del ponente")]
+        [Required]
         public string Ponente { get; set; }
 
-        [Required(ErrorMessage = "debe ingresar la fecha del evento")]
+        [Required]
         public DateTime Fecha { get; set; }
 
 		[Url]
@@ -31,13 +31,13 @@
         [HiddenInput(DisplayValue = false)]
         public string Id { get; set; }
 
-        [Required(ErrorMessage = "debe ingresar el título")]
+        [Required]
         public string Titulo { get; set; }
 
-        [Required(ErrorMessage = "debe ingresar el nombre del ponente")]
+        [Required]
         public string Ponente { get; set; }
 
-        [Required(ErrorMessage = "debe ingresar la fecha del evento")]
+        [Required]
         public DateTime? Fecha { get; set; }
 
 		[Url]
--- a/Agendas/trunk/src/Agendas.Web/Models/PropuestaModel.cs	Tue May 24 19:31:10 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Web/Models/PropuestaModel.cs	Tue May 24 21:37:06 2011 -0300
@@ -12,7 +12,7 @@
 
     public class PropuestaNewModel
     {
-        [Required(ErrorMessage = "debe ingresar el título")]
+        [Required]
         public string Titulo { get; set; }
 
         public string Ponente { get; set; }
@@ -26,12 +26,12 @@
         [HiddenInput(DisplayValue = false)]
         public string Id { get; set; }
 
-        [Required(ErrorMessage = "debe ingresar el título")]
+        [Required]
         public string Titulo { get; set; }
 
         public string Ponente { get; set; }
 
-		[Url(ErrorMessage = "La url ingresada no es válida")]
+		[Url]
 		public string UrlInvitacion { get; set; }
 	}
     
--- a/Agendas/trunk/src/Agendas.sln	Tue May 24 19:31:10 2011 -0300
+++ b/Agendas/trunk/src/Agendas.sln	Tue May 24 21:37:06 2011 -0300
@@ -28,6 +28,8 @@
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Agendas.NHibernate", "Agendas.NHibernate\Agendas.NHibernate.csproj", "{9519A43A-9D5E-4BFD-9F88-AFFC53C9973A}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Agendas.Resources", "Agendas.Resources\Agendas.Resources.csproj", "{444D25FB-FC1C-48DC-9EAD-D4C78F2A10CA}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -74,6 +76,10 @@
 		{9519A43A-9D5E-4BFD-9F88-AFFC53C9973A}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{9519A43A-9D5E-4BFD-9F88-AFFC53C9973A}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{9519A43A-9D5E-4BFD-9F88-AFFC53C9973A}.Release|Any CPU.Build.0 = Release|Any CPU
+		{444D25FB-FC1C-48DC-9EAD-D4C78F2A10CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{444D25FB-FC1C-48DC-9EAD-D4C78F2A10CA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{444D25FB-FC1C-48DC-9EAD-D4C78F2A10CA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{444D25FB-FC1C-48DC-9EAD-D4C78F2A10CA}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE