In ASP.NET Web API, I need to force XML output for a single method but leave the JSON formatter enabled for others. Everything that I have seen on the topic has suggested removing the JSON formatter from the GlobalConfiguration as follows:
// remove JSON formatter
var formatters = GlobalConfiguration.Configuration.Formatters;
formatters.Remove(formatters.JsonFormatter);
This works but disables JSON output application wide. I need to be able to specify a formatter for a specific method or controller without affecting the global configuration. Is this possible or can it only be done via the GlobalConfiguration?
Microsoft introduced per-controller configuration for this specific purpose. You will need to split up your functionality into different controllers, but hopefully that will not be too much of a hassle for your specific goal (it might even be an improvement).
Basically, here is what you do:
Setup basic JSON formatting for the general case
Introduce a specific Controller for the XML methods, and give it a specific configuration:
[XMLControllerConfig]
public class XMLController: ApiController
{
[HttpGet]
public string SomeMethod(string someArgument)
{
return "abc";
}
}
...
class XMLControllerConfigAttribute: Attribute, IControllerConfiguration
{
public void Initialize(HttpControllerSettings controllerSettings,
HttpControllerDescriptor controllerDescriptor)
{
controllerSettings.Formatters.Clear();
controllerSettings.Formatters.Add(new XMLFormatter());
}
}
Related
I enabled health checks for my .Net 5 Web API project
public sealed class Startup
{
public void ConfigureServices(IServiceCollection serviceCollection)
{
serviceCollection.AddHealthChecks();
// ...
}
public void Configure(IApplicationBuilder applicationBuilder, IWebHostEnvironment webHostEnvironment)
{
// ...
applicationBuilder.UseHealthChecks("/health");
// ...
}
}
Unfortunately the health endpoint does not appear in the swagger docs. That's why I created an additional controller
[ApiController]
[Route("[controller]")]
public sealed class HealthController : ControllerBase
{
private readonly HealthCheckService _healthCheckService;
public HealthController(HealthCheckService healthCheckService)
{
_healthCheckService = healthCheckService;
}
[HttpGet]
public async Task<ActionResult<HealthReport>> GetHealthIndication()
{
HealthReport healthReport = await _healthCheckService.CheckHealthAsync();
if (healthReport.Status == HealthStatus.Healthy)
{
return Ok(healthReport);
}
int serviceUnavailableStatusCode = (int) HttpStatusCode.ServiceUnavailable;
return StatusCode(serviceUnavailableStatusCode, healthReport);
}
}
When running the application Swagger generated a lot of models. When opening the health endpoint the page freezes for multiple seconds because it has to load the HealthReport object structure.
I think it is not fine that an API with a single endpoint freezes because of this ... any suggestions for this?
Do I even have to create my own controller, aren't there any integrations yet? I'm looking for a solution like .UseHealthChecks(HealthController.GetHealthIndication)
TLDR;
Add schema mapping for the Exception class in Swagger configuration.
services.AddSwaggerGen(c =>
{
c.MapType<Exception>(() => new OpenApiSchema { Type = "object" });
});
This code would convert Schema with Exception class as an object, thus the behavior you are facing at the client-side would minimize.
Explanation:
Root Cause:
Swagger freezes because the swagger javascript client is trying to create a sample model based on schema fetched from swagger json.
If you look at the Exception class, it contains a large number of nested properties and types. If we instruct the swagger generator to treat the Exception class as a simple object in a created JSON file, the client would not have to spend time creating nested objects. (or you can include TimeSpan class in this conversion as well).
There are multiple ways to solve this issue:
As mentioned above simply instruct the Swagger generator to map type at config level itself.
If you want to create schema based on specific Action (Operation in Swagger context) or Controller (Document in Swagger context), then you can implement respective filters and modify Swagger Document content on the fly. https://github.com/domaindrivendev/Swashbuckle.AspNetCore/blob/master/README.md#override-schema-for-specific-types
Create your own Response model: This makes sense because over time schema of HealthReport could change and thus the output of service could change without realizing it over longer time.
Do I even have to create my own controller, aren't there any integrations yet? I'm looking for a solution.UseHealthChecks(HealthController.GetHealthIndication)
Swashbuckle (Swagger codegen and UI) uses Reflection and Assembly documentation (.xml files) to create swagger documents, thus it is won't scan other assemblies for controllers.
I want to create an image handler, but i am torn between using Web API 2 or just a normal Generic Handler (ashx)
I have implemented both in the past, but which one is the most correct one.
I found an old SO post LINK but is it still really relevant?
WebApi is fully capable and I prefer it. The other answer is right that JSON and XML are default, but you can add your own MediaFormatter and serve any content type for any model. This allows you to perform content negotiation and provide different content based on the Accept header or file extension. Let's pretend our model is a "User". Imagine asking for a "User" as json, xml, jpg, pdf. With WebApi, we can use file extensions or the Accept header and ask for /Users/1 or Users/1.json for JSON, Users/1.jpg for jpg, Users/1.xml for xml, /Users/1.pdf for pdf, etc. All of these could also just be /Users/1 with different Accept headers with quality so your clients could ask for Users/1 with an Accept header asking for jpg first, but fall back to png.
Here is an example of how to create a formatter for .jpg.
public class JpegFormatter : MediaTypeFormatter
{
public JpegFormatter()
{
//this allows a route with extensions like /Users/1.jpg
this.AddUriPathExtensionMapping(".jpg", "image/jpeg");
//this allows a normal route like /Users/1 and an Accept header of image/jpeg
this.SupportedMediaTypes.Add(new MediaTypeHeaderValue("image/jpeg"));
}
public override bool CanReadType(Type type)
{
//Can this formatter read binary jpg data?
//answer true or false here
return false;
}
public override bool CanWriteType(Type type)
{
//Can this formatter write jpg binary if for the given type?
//Check the type and answer. You could use the same formatter for many different types.
return type == typeof(User);
}
public override async Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content,
TransportContext transportContext)
{
//value will be whatever model was returned from your controller
//you may need to check data here to know what jpg to get
var user = value as User;
if (null == user)
{
throw new NotFoundException();
}
var stream = SomeMethodToGetYourStream(user);
await stream.CopyToAsync(writeStream);
}
}
Now we need to register our formatter (typically App_Start/WebApiConfig.cs)
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
...
//typical route configs to allow file extensions
config.Routes.MapHttpRoute("ext", "{controller}/{id}.{ext}");
config.Routes.MapHttpRoute("default", "{controller}/{id}", new { id = RouteParameter.Optional });
//remove any default formatters such as xml
config.Formatters.Clear();
//order of formatters matter!
//let's put JSON in as the default first
config.Formatters.Add(new JsonMediaTypeFormatter());
//now we add our custom formatter
config.Formatters.Add(new JpegFormatter());
}
}
And finally, our controller
public class UsersController : ApiController
{
public IHttpActionResult Get(int id)
{
var user = SomeMethodToGetUsersById(id);
return this.Ok(user);
}
}
Your controller will not have to change as you add different formatters. It simply returns your model and then formatters kick in later in the pipeline. I love formatters as it provides such a rich api. You can read more about formatters on the WebApi website.
The correct one is ashx the reason is the content type. If you use Web Api the content type a.k.a media formatter(format) of your response is the one defined for all your services meaning JSON, XML or oData.
//Global Asax, Web Api register methods is used to defined WebApi formatters
config.Formatters.Insert(0, new System.Net.Http.Formatting.JsonMediaTypeFormatter());
However an image is a binary therefore you need to send the image in its original format and not as JSON or XML
response.AddHeader("content-type", "image/png");
response.BinaryWrite(imageContent);
response.Flush();
That is why the ashx is the right tool for that job.
One additional advantage is that you have more control over your output without the need to code a new "formatter"(the way to make WebApi to resolve this issue) for each image type that you want to return by doing something like in Ashx file:
var png = Image.FromFile("some.png");
png.Save("a.gif", var png = Image.FromFile("some.png");
png.Save("a.gif", ImageFormat.Gif); //Note you can save the new image into a MemoryStream to return it later in the same method.
And you have wide variety of types to play with:
https://msdn.microsoft.com/en-us/library/system.drawing.imaging.imageformat(v=vs.110).aspx
Important: It is clear for all of us that both WebApi and Ashx can return images. I am not saying in any way that you can't achieve this with WebApi all I am saying is why I believe Ashx is the right choice.
I am a big fan of flexibility and customization. I personally would go for httpHandler. So to answer your question, it really depends on your requirements.
First thing WebAPI is the result of evolution all the way from http (GET/POST) calls to web services and the need of being able to transfer data in less cost as opposed to web services. HttpHandlers utilized same concept long time before web apis. Basically web apis are nothing but a http page without its user interface (if you want to).
Few things need to know before choosing HttpHandler or Web Api
development time - whether you know both very well and what will take less time for you to implement
As ManOVision mentioned in his answer, the routing user/1 you can still implement with simple code and httphandler so you don't really need Web API for that. only you may have to right the code manually adding up a little time in development
Flexibility, I personally like this part since I will be able to control the response content type as I want depending upon the data user provides. I don't need to perform session checks and redirect to any page. I can still control this behavior to whatever I want. web API also you can do but mostly things are taken at run time by itself to the configuration we put in place at the development.
rendering web page is the same for both. Although httphandler being easy so why to use Web API?
There might more comparison (As a manager I think from management side as well and not completely technical perspective) so you may have to weigh your options and decide what to do. Since handler file is anyway foundation of web API, I would say it gives more power to developer than web api does. just like a http socket would do more than httphandler.
We have a legacy server code that we want to abandon and develop new one using ServiceStack. Existing clients are not written in .Net. We don't plan to use .Net on the client side at all.
Data between client and server is being exchanged using XML and JSON - at the moment JSON is only used as a return format for the response (just for some of the services available). XML format was defined when the first version of the server solution was created couple of years ago. We don't want to change it.
How do we use ServiceStack to build new RESTful webservices, that will serialize and deserialize data to a format that was designed in the past (please note, that clients will not be written in C#/.Net). We need to contol both: serialization & deserialization. Is that possible to use DTOs and still have control on how are these objects serialized / deserialized?
Adding custom logic via Request / Response Filters
See Request and response filters to see how to add custom logic before and after your service is called. It's best to add these filters via the Request / Response FilterAttributes as it allows you mark only the services that need these filters applied.
The problem with the Request Filter is it happens after the deserialization into the request DTO which is too late to add custom de-serialization logic. To get around this you can register a custom Request binder in your AppHost with:
base.RegisterRequestBinder<MyRequest>(httpReq => ... requestDto);
This gives you access to the IHttpRequest object and lets you add the custom deserialization logic yourself. The other option is to tell ServiceStack to not attempt to deserialize the request itself and instead inject the HttpRequest InputStream so you can deserialize the request yourself:
public class Hello : IRequiresRequestStream {
Stream RequestStream { get; set; }
}
Both these examples are explained on ServiceStack's Serialization and De-Serialization wiki page.
Registering your own Custom Media Type
Another option to be able to return strong-typed DTOs but change the output for certain requests can be done by adding a new custom media type as explained in the Northwind VCard Custom media type example, e.g:
public static void Register(IAppHost appHost)
{
appHost.ContentTypeFilters.Register( "text/x-vcard", SerializeToStream, DeserializeFromStream);
}
...
public static void SerializeToStream(IRequestContext requestContext, object response, Stream stream)
{
var customerDetailsResponse = response as CustomerDetailsResponse;
using (var sw = new StreamWriter(stream))
{
if (customerDetailsResponse != null)
{
WriteCustomer(sw, customerDetailsResponse.Customer);
}
var customers = response as CustomersResponse;
if (customers != null)
{
customers.Customers.ForEach(x => WriteCustomer(sw, x));
}
}
}
This is a good option if you can mount the custom XML responses under a different Content Type, e.g. application/v-xml so it doesn't conflict with the existing XML format/endpoint. Using the ContentType above your HTTP Client can call this custom implementation with ?format=v-xml or using the HTTP Header: Accept: application/v-xml.
If you want to override the built-in XML ContentType you still can but I recommend falling back to the original XmlSerializer implementation for the SerializeStream and DeserializeStream methods if it's not one of the legacy formats you have to support.
By-pass ServiceStack and execute using your own Custom IHttpHandler
Another option is to by-pass ServiceStack completely and instead process the request in your own custom IHttpRequest handler by registering it in ServiceStack's config in your AppHost:
SetConfig(new EndpointHostConfig {
RawHttpHandlers = {
httpReq => return IsLegacyMatch(httpReq) ? new LegacyXmlHandler() : null
}
});
Returning non-null (i.e. any handler) by-passes ServiceStack.
I have created a SoapExtension class to capture the soap request and response from specific web service calls. In order to put this SoapExtension into effect, I have to add an attribute to the method in the generated proxy client.
For example, I've added the AuditSoapCapture attribute to this method:
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://blahblah.com/webservices/AddressSearch", RequestNamespace = "http://blahblah.com/webservices/", ResponseNamespace = "http://blahblah.com/webservices/", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
[blahblah.TriadLite.Core.AuditSoapCapture]
public System.Data.DataSet AddressSearch(string HouseNumber, string StreetName, string ZipCode) {
object[] results = this.Invoke("AddressSearch", new object[] {
HouseNumber,
StreetName,
ZipCode});
return ((System.Data.DataSet)(results[0]));
}
I am looking for a way to add this attribute to specific methods without modifying the generated client proxy, as they will get lost when we regenerate. Can I do this in a another partial class or interface or some other way?
Thanks!
Unfortunately, you'll need to modify the proxy code. The other possibilities you mention will not work - a parial class will not overwrite existing functionality, and there is no way that I'm aware of getting an interface to do what you need (compounded by the fact that there is no way to even let the proxy generator know that you intend to implement an interface).
Something that I've done in the past, in a situation where you have access to the source of the webservice, is to write a little app that will parse the code (as text) in the .asmx.cs file of the webservice to extract the names of all the methods that are tagged with [WebMethod]. Then the app "fixes up" the References.cs by inserting appropriate attributes onto the proxied methods, based on some settings file or somesuch. This works well because the naming conventions in the proxy map very neatly to the method names in the original service.
I may just end up injecting my SoapExtension by putting it into the Web.config. This will cause it to be run on every WS call without a client proxy method attribute. Then, I will modify the SoapExtension to look up the called WS method name on a list, and if it is on the list, then do the rest of the SoapExtension logic. I figure the hit on the list in this small volume application isn't going to kill performance.
6 years ago this was posted... So not sure if this will help anyone at this point.
I ran into something similar with a call to an old SOAP web service that had a dynamically generated proxy class that we didn't want to modify as it was auto-generated from the wsdl by the project. In order to solve this problem here is what we did.
The proxy class generated by wsdl.exe is a partial class. We extended this class like so to add a property with the information we wanted to access in the soapextension. You can add as many properties as you want...
partial class mysoapwebservice
{
public string myproperty{ get; set; }
}
in the web.config we registered the soap extension globaly on the project
<webServices>
<soapExtensionTypes>
<add type="MySoapExtension" priority="1" group="Low"/>
</soapExtensionTypes>
</webServices>
In the code were we created the web service object 'mysoapwebservice' we set the value of the property we needed.
In the soapextension you can get a reference to the web service that was called as well as the values. You can also determine the method call.
`
public class MySoapExtension: SoapExtension
{
public override void ProcessMessage(SoapMessage message)
{
switch (message.Stage)
{
case SoapMessageStage.BeforeSerialize:
{
// web service client object
var webserviceobject= ((SoapClientMessage)message).Client;
// method from web service that was called
var calledMethod = (SoapClientMessage)message).MethodInfo;
// checked the client type of webserviceobject and
//added method / property specific logic here
}
}
}
// other soap extension code
}
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class CriptoExtensionAttribute : SoapExtensionAttribute
[CriptoExtension]
public partial class MainService{
I am using a class in a C# ASP.NET project to allow a script written in some random scripting language to expose webservice methods dynamically - in other words, the script should be able to expose a method of any name with any signature (as long as it's valid, anyway) to the outside world through this SOAP interface (able to add and remove them at will, without needing a hard code change), and as such I need to be able to create a webservice class in C# while being able to dynamically add and remove methods at runtime.
Now, the best plan I've been able to come up with so far is (runtime) generating C# code to represent the webservice, using System.Reflection.Emit to compile it and then loading the assembly at runtime - all whenever the script adds or removes a method to/from the service (should not happen very often, mind).
Does anyone have a better idea than this?
You can modify WSDL by using SoapExtensionReflector class. From Kirk Evans Blog:
The SoapExtensionReflector is called when your type is being reflected over to provide the WSDL definition for your service. You can leverage this type to intercept the reflection call and modify the WSDL output.
The following example removes the first method out of 2 web service methods:
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
public class Service1 : System.Web.Services.WebService
{
[WebMethod]
public string HelloWorld()
{
return "Hello World";
}
[WebMethod]
public int Multiply(int a, int b)
{
return a * b;
}
}
Create a class inherited from SoapExtensionReflector:
namespace TestWebservice
{
public class MyReflector : SoapExtensionReflector
{
public override void ReflectMethod()
{
//no-op
}
public override void ReflectDescription()
{
ServiceDescription description = ReflectionContext.ServiceDescription;
if (description.PortTypes[0].Operations.Count == 2)
description.PortTypes[0].Operations.RemoveAt(0);
if (description.Messages.Count == 4)
{
description.Messages.RemoveAt(0);
description.Messages.RemoveAt(0);
}
foreach (Binding binding in description.Bindings)
{
if (binding.Operations.Count == 2)
binding.Operations.RemoveAt(0);
}
if (description.Types.Schemas[0].Items.Count == 4)
{
description.Types.Schemas[0].Items.RemoveAt(0);
description.Types.Schemas[0].Items.RemoveAt(0);
}
}
}
}
Add this to configuration/system.web section in web.config:
<webServices>
<soapExtensionReflectorTypes>
<add type="TestWebservice.MyReflector, TestWebservice" />
</soapExtensionReflectorTypes>
</webServices>
This should give you a starting point to dynamically removing methods from WSDL document. You would also need to throw NotImplementedException from web method if it is disabled.
Finally, you need to disable web service documentation produced by invoking .asmx endpoint without ?WSDL parameter. Set href attribute of wsdlHelpGenerator element to some URL. You can use DefaultWsdlHelpGenerator.aspx as a starting point for your own documentation handler. See question on web service documentation in XML Files, August 2002.
XMLRPC is fairly dead, isn't it?
SOAP implies a WSDL. How do you generate the WSDL dynamically?
You should look into using WCF. I expect you'll be able to take control of the process of generating the WSDL (and other metadata), yet you should also be able to take control of the processing of incoming messages. In particular, you will be able to examine the incoming messages to determine which script to run, what parameters to pass, etc.
You could create a WCF service with an input and output type of xs:any and handle the incoming request as a raw Message. That would allow you to accept any type of data and return any type of data. You would not use data contracts or static types, just a Message in and a Message out.
The problem with this approach is that generating a proxy from the WSDL really does nothing to help the consumer other than provide a wrapper to call the method. Providing data that is acceptable to the method would require hand-rolling data types, etc which is not that hard, it is just not as intuitive as a hard, typed contract.
Does it have to be a SOAP interface? That sounds like it might be more suitable to a route/REST/etc based API. You could do something in ASP.NET MVC (with a custom IController.Execute method that resolves the action to the method) pretty easily (in fact, I'm working on something very similar for some of my own code at the moment).
For example, you might have routes:
http://myserver/myservice/mymethod
that accepts (either in the body or args) the payload (parameters), and returns the result in the response. In non-MVC you should be able to do something similar with a wildcard-mapped generic handler.
Here is a suggestion:
Use WCF.
Create a WSDL from WCF using
information in the following blog
post:
http://www.pluralsight.com/community/blogs/kirillg/archive/2006/06/18/28380.aspx
You can then publish this information
using MEX.
The services are then open for your
clients to down load the meta data
and call the services.