Given the following string extension method
namespace JHS.ExtensionMethods
{
public static class StringExtensions
{
public static string ToUSAPhone(this String str)
{
return String.Format("{0:(###) ###-####}", Double.Parse(str));
}
}
}
A #using statement was added to the MVC4 Razor view
#using JHS.ExtensionMethods;
and the following string value calls the extension method
#Model.producer.phone.ToUSAPhone()
which results in the following error
'string' does not contain a definition for 'ToUSAPhone'
I also tried putting the namespace in the web.config of the /Views folder and receive the same error.
<pages pageBaseType="System.Web.Mvc.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="JHS.ExtensionMethods"/>
</namespaces>
</pages>
I have verified the extension method works by putting the same call in a C# class
string test=producer.phone.ToUSAPhone();
It seems the reference to the extension method is not available in the MVC4 Razor view but I can't figure out why?
This happens if the type you are trying to use the extension method on is actually a dynamic. Check to see if the exception is being generated by the CSharp RuntimeBinder. If so, you can either use the method as a common or garden static method:
#StringExtensions.ToUSAPhone(Model.producer.phone)
Or you can cast the value to a string:
#(((string)Model.producer.phone).ToUSAPhone())
According to Eric Lippert (formerly of MSFT):
The reason behind the fact that dynamics do not support extension
types is because in regular, non-dynamic code extension methods work
by doing a full search of all the classes known to the compiler for a
static class that has an extension method that match. The search goes
in order based on the namespace nesting and available "using"
directives in each namespace.
That means that in order to get a dynamic extension method invocation
resolved correctly, somehow the DLR has to know at runtime what all
the namespace nestings and "using" directives were in your source
code. There is no mechanism handy for encoding all that information
into the call site.
It's not just if the type you're calling the extension method on is dynamic, but if anything in the expression is dynamic and not cast.
eg this is clearly dynamic:
#ViewBag.ToJSON()
But I first thought Mike's answer did not apply to me because I was doing this :
#(ViewBag.UserProfile.GetJSONProfile().ToJSON())
where ToJSON() is my extension method and GetJSONProfile() just returns object.
I was just spacing out and being stupid but wanted to mention this.
Build your project before adding your custom namespace for the extentions to your View.
There may be yet another trivial reason for this and it happened to me.
The file that I created my extension in had "Content" as value for Build Action property on VS file properties pane.
Switching it to "Compile" immediately fixed the issue, naturally...
i had the exact same problem with the same error message, but in my case in some weird way, i fixed it by putting the ";"
so what was
#{var subti = item.subtitle.Truncate(18)}
was fixed with the ;
#{var subti = item.subtitle.Truncate(18);}
this maybe could help someone
Related
I have an extension method for String that I want to be available on every code behind and class in my solution. The method is sitting in a particular namespace. I'd like everywhere to have access to that namespace without me having to include it in every class.
I've used the "namespaces" tag in the web config to successfully include it on every aspx page, but this does not make it accessible on code behind or elsewhere.
So, is there a similar way to include a namespace everywhere?
So, is there a similar way to include a namespace everywhere?
No, I am afraid that there isn't. If you place the extension method in some of the root namespaces then it will be in scope for the child namespaces. For example:
namespace Foo
{
public static class Extensions
{
public static void Go(this string value)
{
...
}
}
}
will be in scope inside all classes declared in Foo.* namespaces. So you might put the extension method in a root namespace which has the same name as your project and then it will be available everywhere because all classes are automatically generated in child namespaces (unless you change that).
Just put you extensions class into System namespace and it will be available for every String object.
namespace System
{
public static class Extensions
{
public static void M1(this string value)
{
...
}
}
}
No, you cannot.
The namespace section of web.config only provides those namespaces to the markup, but not code-behind.
<configuration>
<system.web>
<pages>
<namespaces>
<add namespace="System.Data" />
<add namespace="System.Text"/>
</namespaces>
</pages>
</system.web>
</configuration>
You must explicitly add namespaces via the using statement in code-behind or add to one of the already included namespaces like System, but that is not recommended.
You'll have put a using statement on every code file that intends to have access to the namespace, you can't "gloabally include."
Usually, it's good form to put your various utilities, static classes, and extension classes in a "Common" project that your other projects all have a dependency on. I've seen this pattern re-used a lot:
Using YourNameSpace.Common.Utilities;
I'm looking for a walkthrough on how to create and use a custom provider for ASP.Net Healthmonitoring.
So far I've only worked with the e-mail provider that generates e-mails on errors. Basically I want to do the same, but with more flexibility:
I want to use the HealthMonitoring features (I don't want to use the Application_OnError event in the global.asax) in a way that allows me have access to an event, that gets thrown like "OnNewHealthMonitoringEntry" with all the information provided in the e-mail, to run custom code.
Edit:
Based on the source code provided here http://www.asp.net/general/videos/how-do-i-create-a-custom-provider-for-logging-health-monitoring-events I was able to build my own custom provider and implement it. Now I want to add some new attributes to configure my custom provider.
Here is what the web.config looks like:
<healthMonitoring>
<bufferModes>
<add name="Log Notification" maxBufferSize="1" maxFlushSize="1" urgentFlushThreshold="1" regularFlushInterval="Infinite" urgentFlushInterval="00:00:10"/>
</bufferModes>
<providers>
<add name="FileEventProvider" buffer="true" bufferMode="Log Notification" type="healthmonitoringtest.FileHealthMonitorEventProvider"/>
</providers>
<profiles>
<add name="Custom" minInstances="1" maxLimit="Infinite" minInterval="00:00:00"/>
</profiles>
<rules>
<add name="File Event Provider" eventName="All Errors" provider="FileEventProvider" profile="Custom"/>
</rules>
</healthMonitoring>
If I attempt to add an attribute to the provider, like this
<providers>
<add name="FileEventProvider" buffer="true" bufferMode="Log Notification" foo="bar" type="healthmonitoringtest.FileHealthMonitorEventProvider"/>
</providers>
I'll get an error saying:
An exception of type
'System.Configuration.ConfigurationErrorsException'
occurred in System.Web.dll but was not
handled in user code Additional
information: Unexpected attribute foo
in the configuration of the
FileEventProvider.
Is it possible to store configuration necessary for custom provider close to the healthMonitoring section? I guess I could include the settings into the appSettings node, but I'd like to configure it somehow with attributes (inside the healthMonitoring node). Is that possible?
Edit2:
You might take a look at this article: http://www.tomot.de/en-us/article/6/asp.net/how-to-create-a-custom-healthmonitoring-provider-that-sends-e-mails
The following series of articles will take you through the basics of using the Health Monitoring System upto creating Custom Events.
Then the following 26 minute video will take you through creating a custom provider that records events to a text-based log file.
UPDATE Based on Comment
Looking at your update and using Reflector to look at the source for the BufferedWebEventProvider class that you base your custom provider on, I have found that the Initialize method in BufferedWebEventProvider does a check at the end to see if there are any attributes that it doesn't recognize. This is done by removing values from the config NameValueCollection parameter as soon as they are assigned to the properties or fields of the BufferedWebEventProvider. Then a check is done to see if the config parameter is empty and if not that means that there are extra attributes added, which causes an exception to be thrown.
As to how to fix this problem, one option is to:
Move the call to base.Initialize to the end of the method
Remove the additional attributes as soon as you assign them to variables just like the provider does.
Something like the following would work:
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
{
foo = config["foo"];
if (String.IsNullOrEmpty(foo))
{
// You can set a default value for foo
}
//remove foo from the config just like BufferedWebEventProvider with the other
//attributes. Note that it doesn't matter if someone didn't proivde a foo attribute
//because the NameValueCollection remains unchanged if you call its Remove method
//and the name doesn't exist.
config.Remove("foo");
base.Initialize(name, config);
}
Hopefully this works out for you.
Hi
I have an assembly called like X.Common.DLL. There is some resources files for multilanguage app. Let's say it Language.resx Language.en-US.resx....etc....
I have a web application which contains this above dll as reference...
So how can I use this resources file in my web applications markup side?
Text="<%$ Resources:Class, ResourceKey %>" is not valid because of "Class" name is in another assembly...
You can easily create a wrapper class that does something like this
public class ResourceWrapper
{
private ResourceManager resourceManager;
public ResourceWrapper()
{
resourceManager = new ResourceManager("Namespace.Common", Assembly.Load("x.common"))
}
public string String(string resourceKey)
{
return ResourceManager.GetString(resourceKey);
}
}
Finding the correct name for the first param to new ResourceManager(...) can be a bit tricky sometimes.
To make it easier for yourself you can call like this:
Assembly.Load("x.common").GetManifestResourceNames() and check the returned results.
If you create a static wrapper, you can make the resource calling code as simple as this:
<%= Resource.String("MyResourceKey") %>
You should reference the other assembly in web.config to expose its content in web forms.
http://msdn.microsoft.com/en-us/library/ms164642.aspx
Edit : more detailed answer due to comments under :
You should complete the pages/namespaces section of the webconfig like this :
<pages>
<namespaces>
...
<add namespace="My.Fully.Qualified.Namespace"/>
</namespaces>
</pages>
Of course the assembly which provides the namespaces should also be referenced (project references, web.config's section)
Then you should be able to write things like "<%= MyResx.MyEntry %>
I have made some progress on the problem I posted about yesterday, so I am rewriting the post.
My problem appears to be related to my use of generics. Here's the relevant part of App.config (formatted with whitespace for readability):
<configSections>
<section
name="NA5300ResolverSynchroDevices"
type="InfrastructureModule.DeviceConfiguration.DeviceConfigurationSection
<NA5300ResolverSynchroModule.NA5300ResolverSynchroConfigurationElement>,
NA5300ResolverSynchroModule">
</section>
</configSections>
<NA5300ResolverSynchroDevices>
<Device deviceName="AzResolverSynchro" busAddress="7"/>
<Device deviceName="ElResolverSynchro" busAddress="8"/>
</NA5300ResolverSynchroDevices>
Here's the class I'm trying to map to the configuration section:
namespace InfrastructureModule.DeviceConfiguration
{
public class DeviceConfigurationSection<T> : ConfigurationSection
where T : DeviceConfigurationElement, new()
{
[ConfigurationProperty("", IsDefaultCollection = true, IsKey = false)]
public DeviceConfigurationElementCollection<T> Devices
{
get { return (DeviceConfigurationElementCollection<T>) base[""]; }
set { base[""] = value; }
}
}
}
Here's the C# code that tries to access the config file:
DeviceConfigurationSection<NA5300ResolverSynchroConfigurationElement> devices =
ConfigurationManager.GetSection("NA5300ResolverSynchroDevices") as
DeviceConfigurationSection<NA5300ResolverSynchroConfigurationElement>;
Here's the exception text I'm getting:
An error occurred creating the configuration section handler for NA5300ResolverSynchroDevices: Could not load type 'InfrastructureModule.DeviceConfiguration.DeviceConfigurationSection<NA5300ResolverSynchroModule.NA5300ResolverSynchroConfigurationElement>' from assembly 'NA5300ResolverSynchroModule'.
I know that in C# generics are instantiated at runtime rather than at compile time (unlike C++). I do not yet know enough about generics to understand what assembly a runtime-generated type is considered to live in when the generic type and the instantiating type live in different assemblies. Above, I told the runtime to look for it in assembly NA5300ResolverSynchroModule. I've also tried telling it to look for it in assembly InfrastructureModule. Neither works.
I am attempting to use a genric type because I will have many config sections for which the corresponding ConfigurationSection-derived types will all be of the form shown above. I want to avoid code duplication.
Can anybody see why my approach is failing and how I can fix it?
Your problem is actually how you've referenced the generic type.
Instead of (shortened):
<section name="..."
type="InfrastructureModule.DeviceConfiguration.DeviceConfigurationSection
<NA5300ResolverSynchroModule.NA5300ResolverSynchroConfigurationElement>,
NA5300ResolverSynchroModule" />
Try
<section name="..."
type="InfrastructureModule.DeviceConfiguration.DeviceConfigurationSection`1[[NA5300ResolverSynchroModule.NA5300ResolverSynchroConfigurationElement, NA5300ResolverSynchroModule]],
NA5300ResolverSynchroModule" />
Note the `1[[...]] rather than <...> or <...> part for the generic type. The part inside the [[...]] can be a full type definition as well - like namespace.class,assembly,token.
The 1 is "generic type with one type parameter". If the type takes 2 "aka SomeType<T,V>", use2. Note that you should put "type, assembly" in the double square brackets, not just "type"
I believe my problem was rooted in the fact that the runtime-generated type I tried to map to a configuration section does not live in an assembly. So, I created a type that does live in an assmebly.
namespace NA5300ResolverSynchroModule
{
public class NA5300ResolverSynchroDeviceConfigurationSection :
DeviceConfigurationSection<NA5300ResolverSynchroConfigurationElement>
{
}
}
I can reference NA5300ResolverSynchroDeviceConfigurationSection just fine in App.config.
I am proper struggling getting that "magic" moment when WCF is configured nicely and jQuery is structuring its requests/understanding responses nicely.
I have a service:
<%# ServiceHost Language="C#" Debug="true" Service="xxx.yyy.WCF.Data.ClientBroker" Factory="System.ServiceModel.Activation.WebScriptServiceHostFactory" %>
This was recommended by the man Rick Strahl to avoid having to define the behaviours within Web.config.
My interface for the WCF service sits in another assembly:
namespace xxx.yyy.WCF.Data
{
[ServiceContract(Namespace = "yyyWCF")]
public interface IClientBroker
{
[OperationContract]
[WebInvoke(Method="POST",BodyStyle=WebMessageBodyStyle.Wrapped,ResponseFormat=WebMessageFormat.Json)]
IClient GetClientJson(int clientId);
}
}
The concrete service class is:
namespace xxx.yyy.WCF.Data
{
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
class ClientBroker : IClientBroker
{
public IClient GetClientJson(int clientId)
{
IClient client=new Client();
// gets and returns an IClient
return client;
}
}
}
My IClient is an Entity Framework class so is decorated with DataContract/DataMember attributes appropriately.
I am trying to call my WCF service using the methods outlined on Rick Strahl's blog at http://www.west-wind.com/weblog/posts/324917.aspx (the "full fat" version). The debugger jumps into the WCF service fine (so my jQuery/JSON is being understood) and gets the IClient and returns it. However, when I return the response, I get various useless errors. The errors I am getting back don't mean much.
I am using POST.
Am I right to be using an Interface instead of a concrete object? As it does get into the WCF service, it does seem to be the encoding of the result that is failing.
Does anyone have any ideas?
At first glance there are three problems with your code:
1: you should use the ServiceKnownTypeAttribute to specify known types when exposing only base types in your operation contracts:
[ServiceContract(Namespace = "yyyWCF")]
public interface IClientBroker
{
[OperationContract]
[ServiceKnownType(typeof(Client))]
[WebInvoke(
Method="GET",
BodyStyle=WebMessageBodyStyle.WrappedRequest,
ResponseFormat=WebMessageFormat.Json)]
IClient GetClientJson(int clientId);
}
2: You should use WebMessageBodyStyle.WrappedRequest instead of WebMessageBodyStyle.Wrapped because the latter is not compatible with WebScriptServiceHostFactory.
3: IMHO using Method="GET" would be more RESTful for a method called GetClientJson than Method="POST"
Another advice I could give you when working with WCF services is to use SvcTraceViewer.exe bundled with Visual Studio. It is a great tool for debugging purposes. All you need is to add the following section to your app/web.config:
<system.diagnostics>
<sources>
<source name="System.ServiceModel"
switchValue="Information, ActivityTracing"
propagateActivity="true">
<listeners>
<add name="sdt"
type="System.Diagnostics.XmlWriterTraceListener"
initializeData= "WcfDetailTrace.e2e" />
</listeners>
</source>
</sources>
</system.diagnostics>
Then invoke the web method and WcfDetailTrace.e2e file will be generated in your web site root directory. Next open this file with SvcTraceViewer.exe and you will see lots of useful information. For example it could say:
Cannot serialize parameter of type
'MyNamespace.Client' (for operation
'GetClientJson', contract
'IClientBroker') because it is not the
exact type 'MyNamespace.IClient' in
the method signature and is not in the
known types collection. In order to
serialize the parameter, add the type
to the known types collection for the
operation using
ServiceKnownTypeAttribute.
Of course you should not forget commenting this section before going into production or you might end up with some pretty big files.
I am 99% sure you cant return an interface. I dont think Interfaces are serializable.
check out this thread
Related to the question, a while ago I posted an article on my blog showing all the steps needed to get a WCF service working together with jQuery code on the client side:
http://yoavniran.wordpress.com/2009/08/02/creating-a-webservice-proxy-with-jquery/