Make my WCF service return json - asp.net

I am trying to make my WCF service method to return JSON-object, but it doesn't work, when I open in a web browser it shows xml.
How can I make this method return JSON?
I have inserted [WebGet(ResponseFormat = WebMessageFormat.Json)], but that didn't help
[WebGet(ResponseFormat = WebMessageFormat.Json)]
protected override IEnumerable<KeyValuePair<string, SampleItem>> OnGetItems()
{
// TODO: Change the sample implementation here
if (items.Count == 0)
{
items.Add("A", new SampleItem() { Value = "A" });
items.Add("B", new SampleItem() { Value = "B" });
items.Add("C", new SampleItem() { Value = "C" });
}
return this.items;
}

In order for this to work, you need to host this with the webHttpBinding and the WebServiceHostFactory in your web.config and service's *.svc file.
You didn't show any web.config or other config - so I cannot really tell what you're doing. But the JSON response format in the WebGet attribute is only supported in the REST-style WCF services. The WebGet attribute is ignored for any of the SOAP-based bindings, e.g. basicHttpBinding, wsHttpBinding, netTcpBinding and so on.
For more information on REST-style WCF Services, check out the WCF REST Developer Center and read up on how to set up and use REST-style WCF services.
Update: in order for your *.svc file to properly work as a REST service that uses the WebGet attribute and returns JSON, you need to make sure to specify the correct service host factory:
<%#ServiceHost Language="C#" Service="YourService"
Factory="System.ServiceModel.Activation.WebServiceHostFactory" %>
By specifying the WebServiceHostFactory, you're telling the WCF runtime to use this service as a REST service, and then all the other pieces should automatically fall into place.

Have you also set the WebHttpBehaviour ? Otherwise, WebGet does not work. See MSDN
And this attribute applies to Service operations, not simple methods. You do not show the rest of your services, but the examples I've seen using WebGet had this attribute in the interface (service contract).

Related

Access MassTransit ConsumeContext in MSDI IServiceCollection.AddTransient service

We need to access a header in our ConsumeContext when adding a transient service.
We have been using IHttpContextAccessor previously to get the headers for a normal http request, and we now need to do similarly for our event consumers.
How would we go about accessing the headers for a consumed event when using MassTransit, when setting up our dependencies/services?
services.TryAddTransient<ISapService>(provider =>
{
var httpContextAccessor = provider.GetService<IHttpContextAccessor>();
httpContextAccessor.HttpContext.Request.Headers.TryGetValue(
"x-plant-id",
out var plantHeader
);
return new SapService(plantHeader);
});
I'm not sure if it works with transient services, but MassTransit does support scoped filters. They're resolved within the consumer scope.

spring MVC controller versioning

I have a spring boot application , which have a spring MVC controller. I am trying to version my rest api using Accept header.
The following is how my Controller looks like
RestController
#RequestMapping(value = "/private/")
public class AppleController {
private final AppleService appleService;
public AppleController(AppleService appleService) {
this.appleService = appleService;
}
#GetMapping(value = "apples/{id}", produces = "application/json; v=1.0",
headers = "Accept=application/json; v=1.0")
public ResponseEntity getByappleId(#PathVariable("id") Long appleId) {
System.out.println("version1");
GetByappleIdResponse response = appleService.findByappleId(appleId);
return new ResponseEntity<>(response, HttpStatus.OK);
}
#GetMapping(value = "apples/{id}", produces = "application/json; v=2.0",
headers = "Accept=application/json; v=2.0")
public ResponseEntity getByappleId2(#PathVariable("id") Long appleId) {
System.out.println("version2");
GetByappleIdResponse response = appleService.findByappleId2(appleId);
return new ResponseEntity<>(response, HttpStatus.OK);
}
Irrespective of the version that I am passing in the Accept header when calling the API always "getByappleId" method is called, hence only version 1 response is returned.
Is there anything wrong in my controller ?
There are many options to implement versioning of REST API:
suggested in the comments approach for manually routing your request;
making version as a part of your Accept header value, f.e.:
(headers = "Accept=application/vnd.name.v1+json")
(headers = "Accept=application/vnd.name.v2+json")
making version as a part of your mapping:
#GetMapping("apples/v1/{id})"
#GetMapping("apples/v2/{id})
So you need to decide which way to go. Some useful links:
Versioning a REST API
Best practices for API versioning?
As described in this answer: https://stackoverflow.com/a/34427044/258813 (and mentioned in the comments) Spring does not support routing using the headers like that.
If you want to support routing via a version header, I would recommend a custom routing condition and annotation - certainly if you are building a large API, it will result in less code and a more elegant solution.
You would define some annotation like #ApiVersion(1) that you can add to any method that is also a request mapping and then add the custom routing condition and it will behave correctly.
I have described using custom routing conditions and annotations (based on subdomains - but that could easily be switched to check headers instead) here: http://automateddeveloper.blogspot.co.uk/2014/12/spring-mvc-custom-routing-conditions.html

Auto-start ASP.NET application hosting WebAPI instance

We're having an odd issue with a WebAPI application hosted by another ASP.NET webapp. The WebAPI controllers are all mapped with Ninject but the ASP.NET host site does not use Ninject.
The issue is that any requests to any of the WebAPI controllers fail with a Ninject error and HTTP 500:
"An error occurred when trying to create a controller of type 'MyObjectsController'. Make sure that the controller has a parameterless public constructor."
However, once even a single request to the main webapp is made (such as opening the login page) then the WebAPI calls all work as expected. The WebAPI is registered and initialized as part of the Application_Start global event. The start event is triggered regardless of whether the first request comes in under the WebAPI or the webapp so it's not bypassing the global startup when coming through the WebAPI before the main app. The WebAPI registration is pretty standard stuff:
GlobalConfiguration.Configure(AddressOf WebApiConfig.Register)
And the Register function itself is nothing unusual:
// Web API configuration and services
var cors = new EnableCorsAttribute("*", "*", "*", "X-Pagination");
//To allow cross-origin credentials in Web API
cors.SupportsCredentials = true;
config.EnableCors(cors);
// To disable host-level authentication inside the Web API pipeline and "un-authenticates" the request.
config.SuppressHostPrincipal();
config.Filters.Add(new HostAuthenticationFilter(Startup.OAuthBearerOptions.AuthenticationType));
// Web API routes
var constraintResolver = new DefaultInlineConstraintResolver();
constraintResolver.ConstraintMap.Add("nonzero", typeof(NonZeroConstraint));
//constraintResolver.ConstraintMap.Add("NonEmptyFolderIds", typeof(NonEmptyFolderIdsConstraint));
config.MapHttpAttributeRoutes(constraintResolver);
var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
The NinjectConfig is also pretty standard:
public static class NinjectConfig
{
/// <summary>
/// THe kernel of Ninject
/// </summary>
public static Lazy<IKernel> CreateKernel = new Lazy<IKernel>(() =>
{
var kernel = new StandardKernel();
kernel.Load(Assembly.GetExecutingAssembly());
RegisterServices(kernel);
return kernel;
});
private static void RegisterServices(KernelBase kernel)
{
kernel.Bind<IMyObjectRepository>().To<MyObjectRepository>().InRequestScope();
...
}
}
An example of the DI usage (again, very basic and standard) is:
public class MyObjectRepository : IMyObjectRepository
{
private readonly IMyOtherObjectRepository _objectRepository;
...
public MyObjectRepository(IMyOtherObjectRepository objectRepository)
{
_objectRepository = objectRepository;
...
}
...
}
We want to avoid the requirement of the initial request to the webapp before the WebAPI is available for requests but nothing seems to be getting us towards a solution.
We initially tried out the IIS preloading/app initialization by setting Start Mode to AlwaysRunning and Start automatically to True in the AppPool config. We also enabled preloadEnabled to true and then added the applicationInitialization config section to the web.config such as the following:
<system.webServer>
...
<applicationInitialization>
<add initializationPage="login.aspx" />
</applicationInitialization>
...
</system.webServer>
However, none of these changes and variations of made any difference to the behavior of the WebAPI. We've scoured the web for more help but are at somewhat of a loss as pretty much everything we've come across points to setting the Start Mode, Start Automatically, preloadEnabled, and applicationInitialization and then it will magically work but that's definitely not our experience.
Does anyone have suggestions or ideas?
Install Ninject integration for WebApi nuget package. It creates a file which initializes Ninject on startup. Here is the doc.

WCF Client Proxies, Client/Channel Caching in ASP.Net - Code Review

long time ASP.Net interface developer being asked to learn WCF, looking for some education on more architecture related fronts - as its not my strong suit but I'm having to deal.
In our current ASMX world we adopted a model of creating ServiceManager static classes for our interaction with web services. We're starting to migrate to WCF, attempting to follow the same model. At first I was dealing with performance problems, but I've tweaked a bit and we're running smoothly now, but I'm questioning my tactics. Here's a simplified version (removed error handling, caching, object manipulation, etc.) of what we're doing:
public static class ContentManager
{
private static StoryManagerClient _clientProxy = null;
const string _contentServiceResourceCode = "StorySvc";
// FOR CACHING
const int _getStoriesTTL = 300;
private static Dictionary<string, GetStoriesCacheItem> _getStoriesCache = new Dictionary<string, GetStoriesCacheItem>();
private static ReaderWriterLockSlim _cacheLockStories = new ReaderWriterLockSlim();
public static Story[] GetStories(string categoryGuid)
{
// OMITTED - if category is cached and not expired, return from cache
// get endpoint address from FinderClient (ResourceManagement SVC)
UrlResource ur = FinderClient.GetUrlResource(_contentServiceResourceCode);
// Get proxy
StoryManagerClient svc = GetStoryServiceClient(ur.Url);
// create request params
GetStoriesRequest request = new GetStoriesRequest{}; // SIMPLIFIED
Manifest manifest = new Manifest{}; // SIMPLIFIED
// execute GetStories at WCF service
try
{
GetStoriesResponse response = svc.GetStories(manifest, request);
}
catch (Exception)
{
if (svc.State == CommunicationState.Faulted)
{
svc.Abort();
}
throw;
}
// OMITTED - do stuff with response, cache if needed
// return....
}
internal static StoryManagerClient GetStoryServiceClient(string endpointAddress)
{
if (_clientProxy == null)
_clientProxy = new StoryManagerClient(GetServiceBinding(_contentServiceResourceCode), new EndpointAddress(endpointAddress));
return _clientProxy;
}
public static Binding GetServiceBinding(string bindingSettingName)
{
// uses Finder service to load a binding object - our alternative to definition in web.config
}
public static void PreloadContentServiceClient()
{
// get finder location
UrlResource ur = FinderClient.GetUrlResource(_contentServiceResourceCode);
// preload proxy
GetStoryServiceClient(ur.Url);
}
}
We're running smoothly now with round-trip calls completing in the 100ms range. Creating the PreloadContentServiceClient() method and adding to our global.asax got that "first call" performance down to that same level. And you might want to know we're using the DataContractSerializer, and the "Add Service Reference" method.
I've done a lot of reading on static classes, singletons, shared data contract assemblies, how to use the ChannelFactory pattern and a whole bunch of other things that I could do to our usage model...admittedly, some of its gone over my head. And, like I said, we seem to be running smoothly. I know I'm not seeing the big picture, though. Can someone tell me what I've ended up here with regards to channel pooling, proxy failures, etc. and why I should head down the ChannelFactory path? My gut says to just do it, but my head can't comprehend why...
Thanks!
ChannelFactory is typically used when you aren't using Add Service Reference - you have the contract via a shared assembly not generated via a WSDL. Add Service Reference uses ClientBase which is essentially creating the WCF channel for you behind the scenes.
When you are dealing with REST-ful services, WebChannelFactory provides a service-client like interface based off the shared assembly contract. You can't use Add Service Reference if your service only supports a REST-ful endpoint binding.
The only difference to you is preference - do you need full access the channel for custom behaviors, bindings, etc. or does Add Service Reference + SOAP supply you with enough of an interface for your needs.

Response.Write JSONP using JQuery and WCF

UPDATE:
The service cannot be activated because it does not support ASP.NET compatibility. ASP.NET compatibility is enabled for this application. Turn off ASP.NET compatibility mode in the web.config or add the AspNetCompatibilityRequirements attribute to the service type with RequirementsMode setting as 'Allowed' or 'Required'.
when i try to access wcf service i get this error: the reason is HttpContext.Current is null, what should i do in this case? any help?
Object reference not set to an instance of an object.
System.Web.Script.Serialization.JavaScriptSerializer s = new System.Web.Script.Serialization.JavaScriptSerializer();
Person p = new Person() { FirstName = "First name", LastName= "last name" };
string json = s.Serialize(p);
System.Web.HttpContext.Current.Response.Write("jsoncallback" + json);} //error
HttpContext is an ASP.Net construct. If you want to be able to access it in your service, then you need to enable ASP.Net Compatibility for your service.
Either through the web.config:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
</system.serviceModel>
Or declaratively:
[AspNetCompatibilityRequirements(RequirementsMode=AspNetCompatibilityRequirementsMode.Required)]
public class MyService : IMyService { ... }
If simple response write is the thing for you, then consider using a simple HttpHandler (by implementing the IHttpHandler interface). The Response object is not meant be used in a WCF Service...
If WCF however is the thing for you (maybe the stack of tech it offers is something you need), then consider using the plumming already there to output json:
[ServiceContract]
public interface IService
{
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.**Json**)]
String DoStuff();
}

Resources