Ajax enabled WCF in MVC returns 404 - c#

I'm trying to add a WCF service to my MVC project to have a general place to put my ajax methods but when i try to call its' methods simply by browsing to the url (e.g. ../Service.svc/HelloWorld) or calling it with jquery ajax I get a 404 page instead.
If i do the same thing in a webforms project, it works without any problem. What am I doing wrong here? Is this not the best practice place to keep ajax methods? Like i said: I want a general place to keep my ajax methods that might be reused from several views so i dont want to put them in the controller of the view if possible
My code:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Service1:IService1
{
public string HelloWorld()
{
return "HelloWorld";
}
}
[ServiceContract]
public interface IService1
{
[OperationContract]
[WebGet]
string HelloWorld();
}
My configuration:
<system.serviceModel>
<services>
<service name="WebApplication1.Service1">
<endpoint address=""
behaviorConfiguration="AJAXEndpoint"
binding="webHttpBinding"
contract="WebApplication1.IService1" />
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="AJAXEndpoint">
<webHttp />
<enableWebScript />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" minFreeMemoryPercentageToActivateService="1" />
</system.serviceModel>

You have to add a ServiceRoute in your Global.asax. You have a 404 simply because there are no routes for this request.
For example this could be
routes.Add(new ServiceRoute("ThePath", new WebServiceHostFactory(), typeof(YourService)));
+1 for asp.net Web Api : this is definitely the recommanded way of building a web api in asp.net, especially in an existing mvc project.

Related

Missing help description for task based WCF service

I'm currently hosting a few web services from within a WPF application. I also have enabled automatic help pages to simplify the service documentation. Every OperationContract is decorated with a Description attribute, containing information about the method.
However, whenever I take a look at my help pages, I realize that only methods with a return type of void will correctly display their Description attribute here. Methods returning Task or Task<t> will only say "Service at localhost:XXXXX/ServiceEndpoint".
As this pattern is used for IPC, I rely a lot on async operation contracts, so most of them will return a Task or Task<t>. Is there any way to fix this issue so the help gets displayed correctly?
namespace App
{
[ServiceContract]
public interface IMainService
{
[OperationContract]
[WebGet(UriTemplate = "visibility")]
[Description("Gets the main window visibility.")]
Task<bool> GetVisibilityAsync();
[OperationContract]
[WebInvoke(UriTemplate = "visibility", Method = "PUT")]
[Description("Sets the main window visibility.")]
Task SetVisibilityAsync(bool isVisible);
[OperationContract]
[WebInvoke(UriTemplate = "menu", Method = "PUT")]
[Description("Navigates to the main menu.")]
void NavigateToMainMenu();
[OperationContract]
[WebInvoke(UriTemplate = "shutdown", Method = "PUT")]
[Description("Requests the application to shutdown.")]
void RequestApplicationShutdown();
}
}
Here is my app.config
<system.web>
<compilation debug="false" targetFramework="4.5" />
</system.web>
<system.serviceModel>
<services>
<service name="App.MainService" behaviorConfiguration="rpcServiceBehavior">
<endpoint binding="webHttpBinding"
contract="App.IMainService"
behaviorConfiguration="webHttpBehavior"
name="RpcEndpoint"/>
<host>
<baseAddresses>
<add baseAddress="http://localhost:25565/main"/>
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="rpcServiceBehavior" >
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="webHttpBehavior">
<webHttp helpEnabled="true" automaticFormatSelectionEnabled="true"/>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
Try to debug with another browser (or in incognito mode).
Explanation:
This is because you probably added a few descriptions, checked it on your browser. Then you added more description tags and checked it again on your browser which, instead of reloading the page, opened the one in cache. Browser will open page in browser in cache instead of reloading it when the page is static.

How to determine if I am using a Restful service or not?

I need to create a Restful service for my application. More I dig deep in to this more I get confused. I understand that a Restful service uses http for CRUD operations which makes it faster and lighter. But I am not sure how to determine if a web service is Restful or not.
However I found some help online that claims to be a Restful service but that has some Custombinding type . Here is how the web.config looks like
<system.serviceModel>
<services>
<service behaviorConfiguration="" name="RestRaw.Service1">
<endpoint address="" behaviorConfiguration="web" contract="RestRaw.IService1" binding="customBinding" bindingConfiguration="RawReceiveCapable"></endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="web">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
<bindings>
<customBinding>
<binding name="RawReceiveCapable">
<webMessageEncoding webContentTypeMapperType="RestRaw.RawContentTypeMapper, RestRaw, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<httpTransport manualAddressing="true" maxReceivedMessageSize="524288000"
transferMode="Streamed" />
</binding>
</customBinding>
</bindings>
</system.serviceModel>
Is that a Restful service. If yes how can that be determined??
I am confused at the moment any suggestions to clarify my doubt would be really appreciated.
In this particular case you can tell it's a REST style webservice by the added behavior.
<endpointBehaviors>
<behavior name="web">
<webHttp/>
</behavior>
</endpointBehaviors>
The webHttp behavior modifies the operation dispatch pipeline and instead of reading a destination action from a SOAP body, it uses the service interface attributes to decide where to route it. Here is a good page on msdn that shows the basics of creating a REST style webservice in WCF. The following example is from that page.
[ServiceContract]
interface ICustomer
{
//"View It" -> HTTP GET
[WebGet( UriTemplate="customers/{id}" )]
Customer GetCustomer( string id ):
//"Do It“ -> HTTP PUT
[WebInvoke( UriTemplate="customers/{id}", Method="PUT" )]
Customer UpdateCustomer( string id, Customer newCustomer );
}
The WebGet attribute matches the GET verb, then the request URI is pattern matched to decide which method to call. Then parts of the URI can be extracted and converted to parameters and passed to the method call. In the second method, UpdateCustomer, the Customer parameter comes from the request body as it's the only parameter that doesn't get matched elsewhere. In order for the request body to be used like this, the webMessageEncoding binding element is used in the custom binding. If you simply use the WebHttpBinding, it does all of this for you. The config you provided is doing it the explicit way.
The web.config file shows a typical WCF application. To check whether it is RESTful, you might learn WCF REST related topics, such as
https://msdn.microsoft.com/en-us/library/dd203052.aspx

What requisities must WCF service have to be used as service/web reference?

I am learning WCF these days and probably don't know where to start. I want to create WCF REST Service, which will be accesible through HTTP requests (GET, PUT...). And at same time I want to be able to add this service as service reference or web reference and use them in the Web Application client as ordinary method. This issue is quite wide so I will by grateful for any hint or direction.
At this time, I have functional services and run them on my hosting. I can add Service Reference and Web Reference. Service reference is better for new code, as I reckognized, because it use WCF communication and thus it contains all former communication channels. When I add these references, I can use reference to GetSimpleDataService, but non of its methods. When I try to add these methods as reference, problem with metadata is noted.
WCF interface:
[ServiceContract]
public interface IGetSimpleDataService
{
[OperationContract]
[WebGet(UriTemplate = "User/{ID}")]
User GetUser(string ID);
[OperationContract]
[ScriptMethod(UseHttpGet = true)]
User GetUserByMethod(string ID);
[OperationContract]
[WebGet]
string ActivationTest();
[OperationContract]
[WebMethod]
string WebMethodTest();
}
Web.config:
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5.2" />
<httpRuntime targetFramework="4.5.2"/>
</system.web>
<system.serviceModel>
<services>
<service name="StoryHubWCFApp.TestStudentService" behaviorConfiguration="serviceBehavior">
<endpoint address=""
binding="webHttpBinding"
contract="StoryHubWCFApp.ITestStudentService"
behaviorConfiguration="web"
/>
</service>
<service name="StoryHubWCFApp.GetSimpleDataService" behaviorConfiguration="serviceBehavior">
<endpoint address=""
binding="webHttpBinding"
contract="StoryHubWCFApp.IGetSimpleDataService"
behaviorConfiguration="web"/>
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="web">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="serviceBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
<behavior name="">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
Now I can get data via GET request, but I want to be able use service with Web/Service reference like this.:
string s = MyServices.ActivationTest();
I assume to use methods like this, which returns or takes values other than int and string I should have [DataContracts]? I understood too, I have to use [WebMethod] or [ScriptMethod], but I wasn't successful so far.
Thanks in regards for any correction.
You can so it almost as smoothly as your example shows...
Since your topic is quite broad I won't go in details just give pointers.
For your own classes, to be able to use them as parameters and/or return types. (in your case User) you have to define what and how to be serialized. You can read about that here:
https://msdn.microsoft.com/en-us/library/ms733127(v=vs.110).aspx
https://msdn.microsoft.com/en-us/library/ms733811(v=vs.110).aspx
Example:
[DataContract]
public class User
{
// This member is serialized.
[DataMember]
string FullName;
// This is not serialized because the DataMemberAttribute
// has not been applied.
private string MailingAddress;
}
Now you are able to use your class.
For calling the service:
You can add service reference: https://msdn.microsoft.com/en-us/library/bb386386.aspx (this would be a generated proxy to your service)
Or you can use ChannelFactory: https://msdn.microsoft.com/en-us/library/ms734681(v=vs.110).aspx
(with this you are in full control of the code, but might need to do more settings, i.e. endpoints.)

Adding WCF service reference in ASP.NET MVC app fails

I'm trying to add a WCF service to my ASP.NET MVC application. After setting it up, I get an error whenever I want to test it.
Here is my code:
BackgroundTask.svc
public class BackgroundTask : IBackgroundTask
{
public void ShutdownVm()
{
}
public void UpdateTable()
{
}
}
IBackgroundTask.cs
[ServiceContract]
public interface IBackgroundTask
{
[OperationContract]
void ShutdownVm();
[OperationContract]
void UpdateTable();
}
Web.config
<system.serviceModel>
<services>
<service behaviorConfiguration="bgtBehaviour" name="IsolutionsAzureManager.Controllers.BackgroundTask">
<endpoint address="BackgroundTask" binding="basicHttpBinding"
bindingConfiguration="" name="" contract="IsolutionsAzureManager.Controllers.IBackgroundTask" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:44304/" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="bgtBehaviour">
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
So, whenever I want to test my WFC service, I get this error:
Error: Cannot obtain Metadata from https://localhost:44304/Controllers/BackgroundTask.svc
Error: The HTML document does not contain Web service discovery information.
Can anyone see the mistake?
Because you are attempting to acquire the mex endpoint over Https, you'll also need to switch to mexHttpsBinding and
to enable the httpsGetEnabled setting:
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
Alternatively, obtain the endpoint via http (http://localhost:44304/Controllers/BackgroundTask.svc) and then just switch back to https once the client has built the service reference artifacts.

ServiceAuthorizationManager not called

I have a very simple ServiceAuthorizationManager (perhaps the simplest) and have followed various tutorials on the web but for some reason none of my breakpoints are hit and this leads to me thinking that its not being called.
Created a WCF Service Application named it WcfTest
Kept the default classes Service1.svc, IService.cs but changed method to return a string
Added a new class that inherits from ServiceAuthorizationManager
Overridden the method CheckAccessCore()
Adjusted web.config so that it uses this manager class
Run the WCF Service Application
Assembly is called WcfTest
All classes live in root of the project no folders or anything
Invoke the method and at this point I am expecting my ServiceAuthorizationManager to be called or am I wrong here? I thought the whole purpose of it was to hit the custom ServiceAuthorizationManager on every request received?
Thanks in advance, Onam.
Any more info required let me know, will be watching this like a hawk as I am very confused when this should apparently be very simple.
[ServiceContract]
public interface IService1
{
[OperationContract]
[WebGet(UriTemplate = "/getIt",ResponseFormat=WebMessageFormat.Json)]
string GetIt();
}
public class Service1 : IService1
{
public string GetIt()
{
return "boo!";
}
}
public class MyServiceMan : ServiceAuthorizationManager
{
protected override bool CheckAccessCore(OperationContext operationContext)
{
try
{
//Some stuff here breakpoint set on above line not hit
return false;
}
catch (Exception e)
{
return false;
}
}
}
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<services>
<service name="WcfTest.Service1">
<endpoint address=""
contract="WcfTest.IService1"
binding="webHttpBinding">
</endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
<serviceAuthorization serviceAuthorizationManagerType="WcfTest.MyServiceMan,WcfTest" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
Are you missing endpoint behavior?
behaviorConfiguration="WebHttpEndpointBehavior"
<endpointBehaviors>
<behavior name="WebHttpEndpointBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
I had the same problem. I resolved it by setting breakpoint in my CustomAuthorizationManager CheckAccessCore method and start debugging my WCF project in Visual Studio. Then I run from my desktop WCF Client App and execute some method and it's done.

Categories