ServiceRoute does not work when routePrefix is a path - wcf

When I try to access my WCF service at the following address it works fine:
http://localhost/webservices/main.svc
Great. But I want to be able to call this service in following way:
http://localhost/api/main
So I am attempting to put in the proper ServiceRoute within the RouteConfig definitions in my MVC. I am able to make the routing work when the routePrefix variable is singular. But I cannot get it to work when routePrefix it is a path such as, as in my case, I want to map a route to ~/api/main.
I've scoured around The Google and this particular question is not common. I am pretty much seeking to accomplish the similar to what is stated in the accepted answer of the following previously posted question on this topic:
Expose WCF services that belong to an Area in MVC app at a routed path
I also attempted to implement a route constraint as suggested here: http://geekswithblogs.net/michelotti/archive/2010/09/22/wcf-rest-services-inside-mvc-projects.aspx
But still get the following error:
No HTTP resource was found that matches the request URI 'http://localhost/api/main'.
No type was found that matches the controller named 'main'.
Here is what I've attempted so far:
Imports System.Web.Mvc
Imports System.Web.Routing
Imports System.ServiceModel.Activation
Imports MyServiceLibrary
Public Class RouteConfig
Public Shared Sub RegisterRoutes(ByVal routes As RouteCollection)
[..other routing stuff...]
routes.Add(New ServiceRoute("api/main", New ServiceHostFactory(), _
GetType(MyServiceLibrary.main)))
routes.MapRoute("Default", "{controller}/{action}/{id}", New With { _
Key .controller = "Default1", _
Key .action = "Index", _
Key .id = UrlParameter.Optional}, _
New With {Key .controller = "^(?!main).*"})
[..other routing stuff...]
End Sub
End Class
Can't seem to figure out the fix on this.
EDIT 2:
When I first posted this question I had a problem with what turned out to be malformed VB syntax.
The original INCORRECT syntax:
routes.Add(new ServiceRoute("api/main", new ServiceHostFactory(), _
typeof(MyServiceLibrary.main)))
The CORRECT vb syntax should be:
routes.Add(New ServiceRoute("api/main", New ServiceHostFactory(), _
GetType(MyServiceLibrary.main)))
Notice that in VB you should use GetType instead of typeof. Fixing this was a good step forward, but did not solve the underlying problem.
EDIT 3:
Well, turns out if I modify the ServiceRoute as follows, then IT WORKS:
routes.Add(New ServiceRoute("main", New ServiceHostFactory(), _
GetType(MyServiceLibrary.main)))
So, the question is how to create the route i desire "api/main"...
EDIT 4:
I thought I might have found the solution here: Can a WCF ServiceRoute Route Prefix contain a path value?
The solution there notably implements WebServiceHostFactory instead of ServiceHostFactory. I tried it, but it didn't work for me.

You should pass in the wcf service type as Type. That is the service defined in your web.config file.
Take a look at this page:
http://blogs.msdn.com/b/endpoint/archive/2010/01/25/using-routes-to-compose-wcf-webhttp-services.aspx

Related

Programmatically modify web.config for a self-hosted service (not via changes to applicationHost.config)

I'm stuck on something I should probably move on from but it's driving me nuts...
I can programmatically update SSL certificate info for a self-hosted WCF service using:
Dim config As Microsoft.Web.Administration.Configuration = _
serverManager.GetApplicationHostConfiguration
site.Bindings.Clear()
Dim binding = site.Bindings.Add(ipport, cert.GetCertHash, store.Name)
serverManager.CommitChanges()
and can also change sections of my local web.config using a known file path starting with:
Dim cfg As System.Configuration.Configuration = _
System.Web.Configuration.WebConfigurationManager.OpenMappedWebConfiguration(ConfigFileMap, target)
but if I try to drill down to system.webServer/security/access using:
Dim accessSection = cfg.GetSection("system.webServer/security")
I get Nothing/null and further digging helpfully produces this status for the section "System.Configuration.IgnoreSection", which apparently indicates that System.Configuration doesn't want to play nice with that specific piece - even though it's not denied access in applicationHost as near as I can tell.
On the other hand, if I try to use Microsoft.Web.Administration I can only figure out how to make the change to applicationHost.config, not to the local web.config.
The only thing that seems to want to put the client certificate requirement (sslFlags setting) in the local web.config is IIS Manager (which also doesn't show the setting correctly if it is located in the applicationHost.config)
Obviously there are all sorts of ways to do this but I can't believe there isn't a simple dot net way (other than editing the xml). Does anyone know what the heck I am doing wrong?
Doh!!! Apparently I need to learn to read the manual (although MS doesn't make it easy).
You can simply do:
Using serverManager As New ServerManager
Dim config As Microsoft.Web.Administration.Configuration = _
serverManager.GetWebConfiguration("site name", "/application")
Dim accessSection As Microsoft.Web.Administration.ConfigurationSection = _
config.GetSection("system.webServer/security/access")
accessSection("sslFlags") = "Ssl,SslRequireCert"
serverManager.CommitChanges()
End Using
Retroactively obvious link: Relevant StackOverflow Question

Consuming WCF return value of List(Of String) in WinForms

I've just started to get rid of Web Services and implement WCF instead. But once I tried to add the following method with a List(Of String) return value, my WCF ServiceReference - which was added successfully - had became unreadable in my WinForms client application code. i.e. It was not defined.
The scenario is pretty simple:
I am creating an OperationContract named ServerMessages with a list of string return value.
This is the interface:
<ServiceContract()>
Public Interface ICommunicationHandler
<OperationContract()>
Function ServerMessages() As List(Of String)
End Interface
And there is the implementation class:
Public Class CommunicationHandler
Implements ICommunicationHandler
Public Function ServerMessages() As List(Of String) _
Implements ICommunicationHandler.ServerMessages
Dim messages As New List(Of String)
messages.Add("First Message")
messages.Add("Second Message")
Return messages
End Function
End Class
There is my client application code:
Dim locServ As New LocalReference.CommunicationHandlerClient
TextBox1.Text += "First Server Messages:" & vbLf & locaServ.ServerMessages(0)
I've tried removing the service reference from the project and re-adding it, but this doesn't solved the problem. On the other hand, removing that specific method ServerMessages() makes the ServiceReference available again in my code. I've even tried to define the type List(Of String) in the Service Interface by adding this attribute:
<ServiceKnownType(GetType(List(Of String)), ServiceContract()>
but nothing had changed.
EDIT
I've noticed this warning in the client application Error window:
Warning 2 Custom tool warning: Cannot import wsdl:port Detail: There
was an error importing a wsdl:binding that the wsdl:port is dependent
on. XPath to wsdl:binding:
//wsdl:definitions[#targetNamespace='http://tempuri.org/']/wsdl:binding[#name='BasicHttpBinding_ICommunicationHandler']
XPath to Error Source:
//wsdl:definitions[#targetNamespace='http://tempuri.org/']/wsdl:service[#name='CommunicationHandler']/wsdl:port[#name='BasicHttpBinding_ICommunicationHandler'] D:\WCTApp\Service
References\LocalReference\Reference.svcmap
Thanks in advance.
My problem was solved by unchecking the [Reuse types in referenced assemblies] in the WCF ServiceReference configuration of my client application. Thanks Steve for letting me having another check on it.
The problem - in this case - was that I've added some references in the service (Google Drive references) which was not defined in my application and therefore causing the ServiceReference not to read the service appropriately. Since I decided not to use these references, I should had eliminated them both from my client application as well as the WCF Service. Now that I stopped using these references in my client application, everything worked as it is supposed to be.
This was my mistake but maybe someone else will fall into the exact same issue and find this situation helpful.

VS: Update Service Reference creates requirement for "Global" prefixes in Reference.vb

VB 2012
WCF & EF 6.1*
I have a client and a web service. When I recompile/change the WS, I go back to my client, and 'Update Service Reference'. Works like a charm-except, the resulting Reference.vb in the client complains that any classes that were defined from the server have a Global. prefix; To be precise, the error description is:
Error 9 Type 'serverNamespace.CountryName' is not defined.
C:\...\UpdateServiceReference\Reference.vb
...where UpdateServiceReference is the client side proxy.
Public Interface IUpdateService
[...]
<System.ServiceModel.OperationContractAttribute(Action:="http://...", ReplyAction:="http://.../IUpdateService/GetClientCountriesResponse")> _
Function GetClientCountries(ByVal placeHolder As Boolean) As serverNamespace.CountryName()
[...]
End Interface
This service reference/proxy on the client only imports from system stuff and the server's namespace's entities. My only settings/imports at the top of the compiler-created Reference.vb are:
Option Strict On
Option Explicit On
Imports System
Imports System.Runtime.Serialization
But here is the really strange (well, confusing) part. In order to clear out the generated errors in the Error List:
Type 'serverNamespace.CountryName' is not defined. Change 'serverNamespace.CountryName' to
'Global.serverNamespace.CountryName'.
I need to do as the compiler suggests above, and change (in Reference.vb) any line with something like this:
Function GetClientCountries(ByVal placeHolder As Boolean) As serverNamespace.CountryName()
...to...
Function GetClientCountries(ByVal placeHolder As Boolean) As Global.serverNamespace.CountryName()
---at EVERY place in both class body & interface... And everything works!
How can I decorate my Web Service to just make it work?
I've already tried using all kinds of "Imports" in the WS code, but nothing has any effect... And just stupidly adding a Global prefix to the existing WS code won't compile...

WebGet UriTemplate fails on dot ('.'/%2E)?

I've been trying for a while now to figure out why this UriTemplate does not work as part of a WCF service and can't seem to get anywhere:
[WebGet(UriTemplate="api/1.0/version")]
string GetVersion();
A quick test shows that UrlTemplateTable matches it fine (output is 'api/1.0/version'):
static void Main(string[] args)
{
Uri prefix = new Uri("http://localhost/");
System.UriTemplateTable table = new System.UriTemplateTable(prefix);
table.KeyValuePairs.Add(new KeyValuePair<UriTemplate, Object>(new UriTemplate("api/1.0/version"), "a"));
table.KeyValuePairs.Add(new KeyValuePair<UriTemplate, Object>(new UriTemplate("api/2.0/version"), "b"));
table.KeyValuePairs.Add(new KeyValuePair<UriTemplate, Object>(new UriTemplate("api/version"), "c"));
Uri uri = new Uri("http://localhost/api/1.0/version");
UriTemplateMatch match = table.MatchSingle(uri);
Console.WriteLine("{0}", match.Template.ToString());
}
The dot is not an illegal character in URLs, RequestPathInvalidCharacters does not exclude it, there are no rewrite rules in place that could interfere. Couldn't find anything in the documentation on it either.
While there is an obvious workaround, not use the dot in the template, I'm curious as to why it fails with 'HTTP 404/The resource cannot be found'.
I ran into the same issue before. I realized it was a limitation in IIS, and nothing to do with WCF. When IIS initially intercepts the request assumes the value following the . represents an extension, so it tries to find a managed handler for that extension. Since it does not find any, it just throws a 404.
Regards
Pablo.

Consume WCF Data service in client application throws error

I am working on WCF Data service which imported stored procedure, as below.
[WebGet]
public List<GetMTSearchResultTest_Result> GettMTSearchResultTest()
{
MediaMarketResearch_PRODEntities ent = new MediaMarketResearch_PRODEntities();
return ent.GetMTSearchResultTest().ToList();
}
when i consuming this in my client application it says error as "The closed type MMRClient.MMRServiceReference.GetMTSearchResultTest_Result does not have a corresponding element settable property."
I am getting this error while bind to the grid view as below.
DataServiceContext context = new DataServiceContext(new Uri("http://localhost:4131/MMRDataService.svc/"));
IEnumerable<GetMTSearchResultTest_Result> empResult = context.Execute<GetMTSearchResultTest_Result>(new Uri("http://localhost:4131/MMRDataService.svc/GettMTSearchResultTest"));
GridView1.DataSource = empResult;
GridView1.DataBind();
Note: I imported this stored proc as complex type.
Please advice me on this.
Regards,
Jaydeep
I think this link may help you (see the selected answer).
Essentially, what the solution may be is to create a partial class for GetMTSearchResultTest_Result and decorate it with a DataServiceKey attribute, providing a non-nullable column that acts as a primary key (although I don't think it has to be unique).
So your partial class would look something like:
[DataServiceKey("YourKeyColumnName")]
public partial class GetMTSearchResultTest_Result {
}
If you're just doing reads, I don't think you'll need any implementation.
Hopefully this works. Let me know if there are issues/questions and I'll update accordingly.
You can always make a new service reference to a non data service. That is to a normal WCF service. You can simply have a [ContractOperation] returning a list of the troubled "complex types" and that's it.
This way you would have two services the original data service and a new normal WCF service. But this shouldn't be such an issue. You don't have to make the troubled "complex type" as a Entity.