Communicate with multiple web service dynamically - c#

I am looking for some advice on how I can do a piece of work I have. Basically I have multiple webservice that takes the same methods and parameters. And it is a pain to always have to get proxy classes, and change the code when a new provider is accepted and I am looking at ways to be able to add the webservice URL in my config and at runtime, be able to compile generate proxy classes and communicate with the remote machine dynamically.
As an example: I have to send data to a method Called UpdateCustomers (int id, string name,string surname,DateTime DateofBirth) to a provider and if We decide to use provider A be able to change the webservice url in config to point to A, or when we decide to change to B etc...
The webservices are .asmx or .svc
I am looking for hint and advice.
Regards

Sounds like a job for WCF Routing.
Depending on how you want to route your calls, you can define message filters which you can use to evaluate if incoming calls fulfil a set of criteria, for example, that a certain value in the soap payload is set to a specific value:
<filters>
<filter name="myXPathFilter1"
filterType="XPath"
filterData="//valueIWantToFilterOn = somevalue"/>
</filters>
You can then register the filter to map to a specific endpoint:
<filterTables>
<table name="myRoutingTable">
<filters>
<add filterName="myXPathFilter1" endpointName="UpdateCustomers1" />
<add filterName="myXPathFilter2" endpointName="UpdateCustomers2" />
...
</filters>
</table>
</filterTables>

Related

Change a Line of Code based on Configuration selected

In my ASP.NET MVC 3 application, I have 2 configurations setup; Play and Live.
Right now, I have to change the following code before loading my application with a configuration based on what I currently have selected:
Mailer.SendMessageTo("playEmailAddress", "MailBody");
// Mailer.SendMessageTo("liveEmailAddress", "MailBody");
So if I have Play configuration selected I'll comment out the liveEmailAddress line and vice versa
What I'd like to do is perhaps make use of the web.config file to change this code for me without manually doing it every time I load up my application with a different configuration by putting the lines of code in the config file and then reading it from the config file from within my class
You should add the "app key" in your web configuration file. Give it anyname like "OptionalEmail" and set the value accordingly.
When you send the email check the value in the configuration file like
If(ConfigurationManager.AppSettings["OptionalEmail"]=="PlayEmail")
SendEmail using PlayEmail address else SendEmail using Work emai
Address.
Hope this help. "ConfigurationManager.AppSettings[use key or index]
Please keep in mind, Config Transformations "xdt" works only when you deploy your web application.
it's generally a good idea to have a configuration parameter named "environment" (or the like).
This link explains how to read from the web.config: http://msdn.microsoft.com/en-us/library/610xe886.aspx.
one way to implement this would be:
var env = "play";
if( ConfigurationManager.AppSettings["environment"]=="live" ) env="live";
var email = env + "EmailAddress";
Mailer.SendMessageTo(email, "MailBody");
as an additional note, if you have multiple developers that each want their own "play"-Address, then you can extend the setting to include the developers machine name:
<appSettings>
<add key="environment" value="play"/>
<add key="liveEmailAddress" value="a#b.com"/>
<add key="myCoolPC-playEmailAddress" value="c#d.com"/>
<add key="otherDevPC-playEmailAddress" value="bubba#test.com"/>
</appSettings>
but then you would have to change the implementation above to prefix the hostname before getting the setting, but only if currently in play-mode.

How to write and configure a custom provider for ASP.Net Healthmonitoring?

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.

How to define endpoint without web.config or httpModule?

I would like to make a RESTful app of HTTPhandlers without having to define every endpoint by making an entry in the web.config, i'd like the style of attaching attributes to a class constructor eg:
public class obj : IHttpHandler
{
[WebGet(UriTemplate = "/accounts/{id}")]
public obj(string id)
{
// this is just an eg, it worild normally include caching and
// a template system
String html = File.ReadAllText("/accounts/accounts.htm");
html.replace("id", id);
httpcontext.current.response.write(html)
}
}
instead of
<httpHandlers>
<clear />
<add verb="GET" path="/accounts/*" type="MyApp.obj" />
</httphandlers>
The way i'm doing it now i have 100's of endpoints in the web.config :( i'd rather define them in the class. And i don't want to make extra files (.asmx) either. I'd like an app of just .htm files with tokens and .cs files
Thanks!
You could automate the registration of the endpoints and so on, with a custom ServiceHost, which overrides the ApplyConfiguration() method, which then virtualizes the configuration so that it does not have to be in the web.config file.
Here's a starting point. It doesn't do exactly what you want, but it illustrates the concept of virtualizing the configuration.

JQuery/WCF without ASP.NET AJAX:

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/

Is there any way to programmatically set the application name in Elmah?

I need to change the app name based on what configuration I'm using in Visual Studio. For example, if I'm in Debug configuration, I want the app name to show as 'App_Debug' in the Application field in the Elmah_Error table. Does anyone have any experience with this? Or is there another way to do it?
This can now be done purely in markup. Just add an applicationName attribute to the errorLog element in the <elmah> section of the web.config file. Example:
<errorLog type="Elmah.SqlErrorLog, Elmah"
connectionStringName="connectionString" applicationName="myApp" />
I've tested this and it works both when logging an exception and when viewing the log via Elmah.axd.
In the case of the OP, one would imagine it can be set programatically too but I didn't test that. For me and I imagine for most scenarios the markup approach is sufficient.
By default, Elmah uses the AppPool's application GUID as the default application name. It uses this as the key to identify the errors in the Elmah_Error table when you look at the web interface that's created through it's HTTP Module.
I was tasked to explore this option for my company earlier this year. I couldn't find a way to manipulate this by default since Elmah pulls the application name from HttpRuntime.AppDomainAppId in the ErrorLog.cs file. You could manipulate it by whatever key you want; however, that is the AppPool's GUID.
With that said, I was able to manipulate the ErrorLog.cs file to turn Elmah into a callable framework instead of a handler based one and allow for me set the ApplicationName. What I ended up doing was modifying ErrorLog.cs to include a property that allowed me to set the name as below:
public virtual string ApplicationName
{
get
{
if (_applicationName == null) { _applicationName = HttpRuntime.AppDomainAppId; }
return _applicationName;
}
set { _applicationName = value; }
}
What you will probably need to do is adjust this differently and set the ApplicationName not to HttpRuntime.AppDomainAppId but, instead, a value pulled from the web.config. All in all, it's possible. The way I did it enhanced the ErrorLog.Log(ex) method so I could use Elmah has a callable framework beyond web applications. Looking back I wish I did the app/web.config approach instead.
One thing to keep in mind when changing the application name in Elmah. The http handler that generates the /elmah/default.aspx interface will no longer work. I'm still trying to find time to circle back around to such; however, you may need to look into creating a custom interface when implementing.

Categories