ConfigurationSection with nested ConfigurationElementCollections - configurationsection

Hopefully, I can present this problem to the brain trust of this site and someone will see my mistake.
I am working on a project where email text needs to be "mail merged" with information found in the properties of various internal classes. A typical symbol found in the email text might look like "{member name}, {mobile phone}, etc."
I would like to define the symbols and the classes they are found in using a ConfigurationSection in web.config. Here is my proposed configuration section:
<EmailSymbols>
<SymbolClasses>
<SymbolClass name="OHMember">
<Symbol name="Member Name" template="{0} {1}">
<add index="0" value="SMFirstName" />
<add index="1" value="SMLastName" />
</Symbol>
<Symbol name="Phone" template="{0}">
<add index="0" value="SMPhone" />
</Symbol>
</SymbolClass>
<SymbolClass name="Form">
<Symbol name="Contact Name" dataname="ContactName" />
</SymbolClass>
</SymbolClasses>
</EmailSymbols>
...and the code that I am trying to parse it with:
public class EmailSymbols : ConfigurationSection {
[ConfigurationProperty("SymbolClasses", IsRequired = true)]
public SymbolClassCollection SymbolClasses {
get {
return this["SymbolClasses"] as SymbolClassCollection;
}
}
}
[ConfigurationCollection(typeof(SymbolClass), AddItemName = "SymbolClass")]
public class SymbolClassCollection : ConfigurationElementCollection {
protected override ConfigurationElement CreateNewElement() {
return new SymbolClass();
}
protected override object GetElementKey(ConfigurationElement element) {
return ((SymbolClass)element).Name;
}
}
[ConfigurationCollection(typeof(Symbol), AddItemName = "Symbol")]
public class SymbolClass : ConfigurationElementCollection {
[ConfigurationProperty("name", IsRequired = true, IsKey = true)]
public String Name {
get {
return this["name"] as String;
}
}
protected override ConfigurationElement CreateNewElement() {
return new Symbol();
}
protected override object GetElementKey(ConfigurationElement element) {
return ((Symbol)element).Name;
}
}
[ConfigurationCollection(typeof(TemplateValue), AddItemName = "add")]
public class Symbol : ConfigurationElementCollection {
[ConfigurationProperty("name", IsRequired = true, IsKey = true)]
public String Name {
get {
return this["name"] as String;
}
}
[ConfigurationProperty("template", IsRequired = false)]
public String Template {
get {
return this["template"] as String;
}
}
[ConfigurationProperty("dataname", IsRequired = false)]
public String DataName {
get {
return this["dataname"] as String;
}
}
protected override ConfigurationElement CreateNewElement() {
return new TemplateValue();
}
protected override object GetElementKey(ConfigurationElement element) {
return ((TemplateValue)element).Index;
}
}
public class TemplateValue : ConfigurationElement {
[ConfigurationProperty("index", IsRequired = false, IsKey = true)]
public Int32 Index {
get {
return this["index"] == null ? -1 : Convert.ToInt32(this["index"]);
}
}
[ConfigurationProperty("value", IsRequired = false)]
public String Value {
get {
return this["value"] as String;
}
}
}
When I parse the section with this statement:
symbols = ConfigurationManager.GetSection("EmailSymbols") as EmailSymbols;
I receive this error message: "Unrecognized element 'Symbol'."
This is simply an area of .NET that I don't know my way around. Any help that anyone could give would be most appreciated.
Does my XML definition make sense and is it in the correct form? I want a collection of SymbolClass, each containing a collection of Symbol, each containing a collection of TemplateValue.
Again, thanks for your help.
Best Regards,
Jimmy

You could try to override the Init() method of the SymbolClass class:
protected override void Init()
{
base.Init();
this.AddElementName = "Symbol";
}
You an also remove [ConfigurationCollection(typeof(SymbolClass), AddItemName = "SymbolClass")] and the others like it from above the class declarations as their not doing anything.

Related

Why is this <p:selectManyMenu> not working? (getAllDatasourceGroups() is not even called once)

My problem is about this primefaces tag:
<p:selectManyCheckbox id="datasourceGroup" value="#{sessionBean.datasourceGroups}" converter="datasourceGroupConverter">
<f:selectItems value="#{sesionBean.getAllDatasourceGroups()}" var="group" itemLabel="#{group.toString()}" itemValue="#{group}" />
</p:selectManyCheckbox>
It does not render any visible output (checkboxes) at all. From logging output i know that the 'sessionBean.getAllDatasourceGroups()' method is not even called once during page refresh. only the 'sessionBean.getDatasourcegroups()' getter for the 'datasourceGroups' property is called once.
And i can't figure out what the problem is. I have very similar usecases of <p:selectManyMenu> and <p:selectOneMenu> on the same page and they work fine. So i have a basic understanding of how this works...or so i thought :-)
here are the other relevant parts of the code for reference:
SessionBean:
#ManagedBean
#SessionScoped
public class SessionBean implements Serializable {
private List<DatasourceGroup> datasourceGroups = new ArrayList<>();
public List<DatasourceGroup> getDatasourceGroups() {
return datasourceGroups;
}
public void setDatasourceGroups(List<DatasourceGroup> datasourceGroups) {
this.datasourceGroups = datasourceGroups;
}
public List<DatasourceGroup> getAllDatasourceGroups() {
List<DatasourceGroup> list = Arrays.asList(DatasourceGroup.values());
return list;
}
}
DatasourceGroup Enum:
public enum DatasourceGroup {
KUNDEN (Permission.ZugriffKunden),
INKASSO (Permission.ZugriffInkasso),
INTERESSENTEN (Permission.ZugriffInteressenten),
WARN (Permission.ZugriffWarnadressen);
private Permission permissionNeeded;
DatasourceGroup(Permission permission) {
this.permissionNeeded=permission;
}
public Permission getPermissionNeeded() {
return permissionNeeded;
}
}
And the DatasourceGroupConverter:
#FacesConverter("datasourceGroupConverter")
public class DatasourceGroupConverter implements Converter {
#Override
public Object getAsObject(FacesContext fc, UIComponent uic, String value) {
if (Toolbox.isNullOrEmpty(value))
return null;
try {
return DatasourceGroup.valueOf(value);
} catch (IllegalArgumentException e) {
throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Conversion Error:",
"'" + value + "' is not a valid datasource group name"));
}
}
#Override
public String getAsString(FacesContext fc, UIComponent uic, Object object) {
if(object != null && object instanceof DatasourceGroup) {
return ((DatasourceGroup)object).toString();
}
return null;
}
}
I'm using primefaces 6.0 by the way.

MVC6 alternative to #Html.DisplayFor

MVC6 introduces Tag Helpers which is a better way compared to using #Html.EditorFor, etc. However I have not found any Tag Helper that would be an alternative to #Html.DisplayFor.
Of course I can use a variable directly on a Razor page, such as #Model.BookingCode. But this does not allow to control formatting.
With MVC6, what's conceptually correct way for displaying a value of a model property?
#Html.DisplayFor still exists and can still be used.
The difference between HtmlHelpers and TagHelpers is that HtmlHelpers choose which html elements to render for you whereas TagHelpers work with html tags that you add yourself so you have more full control over what html element is used. You do have some control over the markup using templates with HtmlHelpers but you have more control with TagHelpers.
So you should think in terms of what html markup do I want to wrap this model property in and add that markup around the property itself using #Model.Property with some markup around it or continue using DisplayFor if you prefer to let the helper decide.
You can create your own tag helper
namespace MyDemo.TagHelpers
{
[HtmlTargetElement("p", Attributes = ForAttributeName)]
public class DisplayForTagHelper : TagHelper
{
private const string ForAttributeName = "asp-for";
[HtmlAttributeName(ForAttributeName)]
public ModelExpression For { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (output == null)
{
throw new ArgumentNullException(nameof(output));
}
var text = For.ModelExplorer.GetSimpleDisplayText();
output.Content.SetContent(text);
}
}
}
Add use it in view:
<p asp-for="MyProperty" class="form-control-static"></p>
I have been using this as a display tag helper.
[HtmlTargetElement("*", Attributes = ForAttributeName)]
public class DisplayForTagHelper : TagHelper
{
private const string ForAttributeName = "asp-display-for";
private readonly IHtmlHelper _html;
public DisplayForTagHelper(IHtmlHelper html)
{
_html = html;
}
[HtmlAttributeName(ForAttributeName)]
public ModelExpression Expression { get; set; }
public IHtmlHelper Html
{
get
{
(_html as IViewContextAware)?.Contextualize(ViewContext);
return _html;
}
}
[HtmlAttributeNotBound]
[ViewContext]
public ViewContext ViewContext { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
if (context == null)
throw new ArgumentNullException(nameof(context));
if (output == null)
throw new ArgumentNullException(nameof(output));
var type = Expression.Metadata.UnderlyingOrModelType;
if (type.IsPrimitive)
{
output.Content.SetContent(Expression.ModelExplorer.GetSimpleDisplayText());
}
// Special Case for Personal Use
else if (typeof(Dictionary<string, string>).IsAssignableFrom(type))
{
output.Content.SetHtmlContent(Html?.Partial("Dictionary", Expression.ModelExplorer.Model));
}
else
{
var htmlContent = Html.GetHtmlContent(Expression);
output.Content.SetHtmlContent(htmlContent);
}
}
}
public static class ModelExpressionExtensions
{
public static IHtmlContent GetHtmlContent(this IHtmlHelper html, ModelExpression expression)
{
var ViewEngine = html.ViewContext.HttpContext.RequestServices.GetService(typeof(ICompositeViewEngine)) as ICompositeViewEngine;
var BufferScope = html.GetFieldValue<IViewBufferScope>();
var htmlContent = new TemplateBuilder(ViewEngine, BufferScope, html.ViewContext, html.ViewContext.ViewData, expression.ModelExplorer, expression.Name, null, true, null).Build();
return htmlContent;
}
public static TValue GetFieldValue<TValue>(this object instance)
{
var type = instance.GetType();
var field = type.GetFields(BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance).FirstOrDefault(e => typeof(TValue).IsAssignableFrom(e.FieldType));
return (TValue)field?.GetValue(instance);
}
}
try below code
public class movie
{
public int ID { get; set; }
[DisplayName("Movie Title")]
public string Title { get; set; }
}
///////////////////////////////////////////////////
#model IEnumerable<MvcMovie.Models.Movie>
<h1>Show List Movies</h1>
<label asp-for="ToList()[0].Title">< /label>
#foreach (var movie in Model)
{
#movie.Title
}

How to write a function that can be available in all Razor views?

I'm trying to write a function that can bring a language resource from database in MVC 5 and Razor,
I want it to be very simple to use, for example, the following function should just get some text:
#T("ResourceType", "ResourceName")
I don't want to use #this. - just the the function name...
I saw some posts about it mentioning the line below, but still trying to understand how to do it
public abstract class WebViewPage<TModel> : System.Web.Mvc.WebViewPage<TModel>
Any help will be greatly appreciated.
Thanks in advance.
I finally found a way to do it, inspired by the NopCommerce project, see the code below.
The code can be used in any Razor (cshtml) view like this:
<h1>#T("StringNameToGet")</h1>
Also, note that pageBaseType needs to be updated with the correct new namespace,
this is the web.config in the Views folder - not the main one, should look like this:
<system.web.webPages.razor>
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<pages pageBaseType="MyNameSpace.Web.Extensions.WebViewPage">
<namespaces>
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Optimization"/>
<add namespace="System.Web.Routing" />
<add namespace="APE.Web" />
</namespaces>
</pages>
The code:
namespace MyNameSpace.Web.Extensions
{
public delegate LocalizedString Localizer(string text, params object[] args);
public abstract class WebViewPage : WebViewPage<dynamic>
{
}
/// <summary>
/// Update the pages element /views/web.config to reflect the
/// pageBaseType="MyNameSpace.Web.Extensions.WebViewPage"
/// </summary>
/// <typeparam name="TModel"></typeparam>
public abstract class WebViewPage<TModel> : System.Web.Mvc.WebViewPage<TModel>
{
private Localizer _localizer;
/// <summary>
/// Get a localized resources
/// </summary>
public Localizer T
{
get
{
if (_localizer == null)
{
//null localizer
//_localizer = (format, args) => new LocalizedString((args == null || args.Length == 0) ? format : string.Format(format, args));
//default localizer
_localizer = (format, args) =>
{
var resFormat = SampleGetResource(format);
if (string.IsNullOrEmpty(resFormat))
{
return new LocalizedString(format);
}
return
new LocalizedString((args == null || args.Length == 0)
? resFormat
: string.Format(resFormat, args));
};
}
return _localizer;
}
}
public string SampleGetResource(string resourceKey)
{
const string resourceValue = "Get resource value based on resourceKey";
return resourceValue;
}
}
public class LocalizedString : System.MarshalByRefObject, System.Web.IHtmlString
{
private readonly string _localized;
private readonly string _scope;
private readonly string _textHint;
private readonly object[] _args;
public LocalizedString(string localized)
{
_localized = localized;
}
public LocalizedString(string localized, string scope, string textHint, object[] args)
{
_localized = localized;
_scope = scope;
_textHint = textHint;
_args = args;
}
public static LocalizedString TextOrDefault(string text, LocalizedString defaultValue)
{
if (string.IsNullOrEmpty(text))
return defaultValue;
return new LocalizedString(text);
}
public string Scope
{
get { return _scope; }
}
public string TextHint
{
get { return _textHint; }
}
public object[] Args
{
get { return _args; }
}
public string Text
{
get { return _localized; }
}
public override string ToString()
{
return _localized;
}
public string ToHtmlString()
{
return _localized;
}
public override int GetHashCode()
{
var hashCode = 0;
if (_localized != null)
hashCode ^= _localized.GetHashCode();
return hashCode;
}
public override bool Equals(object obj)
{
if (obj == null || obj.GetType() != GetType())
return false;
var that = (LocalizedString)obj;
return string.Equals(_localized, that._localized);
}
}
}

Force WCF Rest client to use Json deserializer regardless of content-type

How to force WCF Rest client to use Json deserializer regardless of content-type?
I am invoking a REST based web service through WCF.
The service returns JSON body, but has content-type "Application/xml". The WCF framework is now giving me the XmlException.
public class MessageFormatter : IClientMessageFormatter
{
private readonly IClientMessageFormatter _formatter;
public MessageFormatter(IClientMessageFormatter formatter)
{
_formatter = formatter;
}
public object DeserializeReply(System.ServiceModel.Channels.Message message, object[] parameters)
{
return _formatter.DeserializeReply(message, parameters);
}
}
that _formatter.DeserializeReply is throwing XmlException. I can't find any example anywhere to force json deserialization on reply.
Edit - The "message" object when moused over is throwing "{... Error reading body: System.Xml.XmlException: The data at the root level is invalid. Line 1, position 1. ...}"
That same object in another one of my project that communicate with a different REST service (Picasa web services) has a what seems like a xml serialised version of JSON object?? So the problem seems further up the stream. I need to find where this object is originating from. I'll go play around with MessageEncoder class.
Edit - (Adding more info)
public class MyBinding : WebHttpBinding
{
public MyBinding(WebHttpSecurityMode mode)
: base(mode)
{
}
public override BindingElementCollection CreateBindingElements()
{
var result = base.CreateBindingElements();
var replacements = result.OfType<MessageEncodingBindingElement>().ToList();
foreach (var messageEncodingBindingElement in replacements)
{
var index = result.IndexOf(messageEncodingBindingElement);
result.Remove(messageEncodingBindingElement);
result.Insert(index, new MyMessageEncodingBindingElement(messageEncodingBindingElement));
}
return result;
}
}
public class MyMessageEncodingBindingElement : MessageEncodingBindingElement
{
private readonly MessageEncodingBindingElement _element;
public MyMessageEncodingBindingElement(MessageEncodingBindingElement element)
{
_element = element;
}
public override BindingElement Clone()
{
var result = _element.Clone();
if (result is MessageEncodingBindingElement)
return new MyMessageEncodingBindingElement(result as MessageEncodingBindingElement);
return result;
}
public override MessageEncoderFactory CreateMessageEncoderFactory()
{
return new MyMessageEncoderFactory(_element.CreateMessageEncoderFactory());
}
}
The method CreateMessageEncoderFactory() is never called even when the constructor and Clone method are hit when breakpoints are set. Any help? I'm trying to set a custom MessageEncoder and MessageEncoderFactory class to modify the instantiation process of the Message object.
You can use a WebContentTypeMapper for that. That's a property of the WebHttpBinding, and you can customize how the deserialization will be done by the encoder from that binding, including forcing it to always use the JSON deserializer, regardless of the incoming message's Content-Type. The code below shows how this can be done.
public class StackOverflow_13225272
{
[DataContract]
public class Person
{
[DataMember]
public string Name { get; set; }
[DataMember]
public int Age { get; set; }
public override string ToString()
{
return string.Format("Person[Name={0},Age={1}]", Name, Age);
}
}
[ServiceContract]
public interface ITest
{
[WebGet(ResponseFormat = WebMessageFormat.Json)]
Person GetPerson(string responseContentType);
}
public class Service : ITest
{
public Person GetPerson(string responseContentType)
{
WebOperationContext.Current.OutgoingResponse.ContentType = responseContentType;
return new Person { Name = "John Doe", Age = 29 };
}
}
class AllJsonContentTypeMapper : WebContentTypeMapper
{
public override WebContentFormat GetMessageFormatForContentType(string contentType)
{
return WebContentFormat.Json;
}
}
public static void Test()
{
string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
WebServiceHost host = new WebServiceHost(typeof(Service), new Uri(baseAddress));
host.Open();
Console.WriteLine("Host opened");
#if USE_NETFX4
// This works on .NET 4.0 and beyond
WebHttpBinding binding = new WebHttpBinding();
binding.ContentTypeMapper = new AllJsonContentTypeMapper();
#else
// This works on .NET 3.5
CustomBinding binding = new CustomBinding(new WebHttpBinding());
binding.Elements.Find<WebMessageEncodingBindingElement>().ContentTypeMapper = new AllJsonContentTypeMapper();
ChannelFactory<ITest> factory = new ChannelFactory<ITest>(binding, new EndpointAddress(baseAddress));
#endif
ChannelFactory<ITest> factory = new ChannelFactory<ITest>(binding, new EndpointAddress(baseAddress));
factory.Endpoint.Behaviors.Add(new WebHttpBehavior());
ITest proxy = factory.CreateChannel();
Console.WriteLine("With JSON: {0}", proxy.GetPerson("application/json"));
Console.WriteLine("With XML: {0}", proxy.GetPerson("application/xml"));
Console.Write("Press ENTER to close the host");
Console.ReadLine();
host.Close();
}
}
This might work.
public class ForceJsonClientMessageFormatter : IClientMessageFormatter
{
private readonly DataContractJsonSerializer _jsonSerializer;
public ForceJsonClientMessageFormatter(Type responseType)
{
_jsonSerializer = new DataContractJsonSerializer(responseType);
}
public Message SerializeRequest(MessageVersion messageVersion, object[] parameters)
{
throw new NotImplementedException("This client message formatter is for replies only!");
}
public object DeserializeReply(Message message, object[] parameters)
{
string messageBody = message.GetBody<string>();
using (MemoryStream messageStream = new MemoryStream(Encoding.UTF8.GetBytes(messageBody)))
{
messageStream.Seek(0, SeekOrigin.Begin);
object deserializedObject = _jsonSerializer.ReadObject(messageStream);
return deserializedObject;
}
}
}
public class ForceJsonWebHttpBehavior : WebHttpBehavior
{
protected override IClientMessageFormatter GetReplyClientFormatter(OperationDescription operationDescription, ServiceEndpoint endpoint)
{
return new ForceJsonClientMessageFormatter(operationDescription.Messages[1].Body.ReturnValue.Type);
}
}
I haven't tried it, but I think this will work. You can create a custom IClientMessageFormatter which overwrites the message format to Json, wrap that in a behavior, and then apply that behavior to your client endpoint configuration.
public class ForceJsonClientMessageFormatterDecorator : IClientMessageFormatter
{
private readonly IClientMessageFormatter _decoratedFormatter;
public ForceJsonClientMessageFormatterDecorator(IClientMessageFormatter decoratedFormatter)
{
_decoratedFormatter = decoratedFormatter;
}
public object DeserializeReply(Message message, object[] parameters)
{
message.Properties[WebBodyFormatMessageProperty.Name] = new WebBodyFormatMessageProperty(WebContentFormat.Json);
return _decoratedFormatter.DeserializeReply(message, parameters);
}
public Message SerializeRequest(MessageVersion messageVersion, object[] parameters)
{
return _decoratedFormatter.SerializeRequest(messageVersion, parameters);
}
}
public class ForceJsonWebHttpBehavior : WebHttpBehavior
{
protected override IClientMessageFormatter GetReplyClientFormatter(OperationDescription operationDescription, ServiceEndpoint endpoint)
{
IClientMessageFormatter decoratedFormatter = base.GetReplyClientFormatter(operationDescription, endpoint);
return new ForceJsonClientMessageFormatterDecorator(decoratedFormatter);
}
}

Ninject Load FromAssembliesInPath with a Constructor

if i say have code that works like this:
private static void LoadFromAssemblies(IKernel kernel)
{
string appPath = HttpContext.Current.Request.MapPath(HttpContext.Current.Request.ApplicationPath);
kernel.Scan(a =>
{
a.FromAssembliesInPath(string.Format(#"{0}\Extensions", appPath));
a.AutoLoadModules();
a.BindWithDefaultConventions();
a.InRequestScope();
});
}
and just assume that each class defined in the target assembly has a string argument in the constructor, how would i go about passing in the string argument from the code above?
Do i instead use an Interceptor?
Thanks in advance, John
In my project into some repositories I pass ISession (nHibernate) and to others connectionString for DataContext(Linq2SQL)
To pass the connection string I have created LinqConfiguration class
public class LinqConfiguration : ILinqConfiguration
{
private readonly string _connectionString;
public LinqConfiguration(string connectionString)
{
_connectionString = connectionString;
}
public string GetConnectionString()
{
return _connectionString;
}
}
My repository looks like this:
public class WebClientRepository : IWebClientRepository
{
private readonly WebClientDataClassesDataContext datacontext;
private ILinqConfiguration _linqconfig;
public WebClientRepository(ILinqConfiguration linqconfig)
{
_linqconfig = linqconfig;
datacontext = new WebClientDataClassesDataContext(_linqconfig.GetConnectionString());
}
//....
}
and binding using Conventions:
public class LinqRepositoryModule: NinjectModule
{
public override void Load()
{
Bind<ILinqConfiguration>()
.To<LinqConfiguration>()
.WithConstructorArgument("connectionString",
ConfigurationManager.ConnectionStrings["ApplicationServices"].ConnectionString
);
IKernel ninjectKernel = this.Kernel;
ninjectKernel.Scan(kernel =>
{
kernel.FromAssemblyContaining<IWebClientRepository>();
kernel.FromAssemblyContaining<WebClientRepository>();
kernel.Where(t => t != typeof(LinqConfiguration)); // interface is in the same assembly and it is already binded
kernel.BindWithDefaultConventions();
kernel.AutoLoadModules();
kernel.InRequestScope();
});
}
}