Imagine a simple controller action IEnumerable<BaseType> Get(). It returns an enumeration of different types all deriving from BaseType.
When the client requests XML, the result is something like this:
<ArrayOfBaseType>
<BaseType i:type="DerivedType1"><A>value</A></BaseType>
<BaseType i:type="DerivedType2"><B>value</B></BaseType>
<BaseType i:type="DerivedType3"><C>value</C></BaseType>
</ArrayOfBaseType>
As you can see, the type of the derived class is transmitted in the i:type attribute.
If the client requests JSON however, this information is missing:
[
{"A":"value"},
{"B":"value"},
{"C":"value"}
]
How to fix this?
The following change is necessary:
In the WebApiConfig.cs the following line needs to be added:
config.Formatters.JsonFormatter.SerializerSettings.TypeNameHandling =
TypeNameHandling.Auto;
This will automatically result in a new property $type when needed.
If you write your class following:
public class MyClass
{
// properties here
public string IType
{
get
{
return this.GetType().Name;
}
set { }
}
}
Maybe, it will help you
Related
I am trying to create a .NET5 WebApi delete method in a controller class where this method receives several "ids" that will be used for deleting some entities.
I realized when building the delete request on the client side that specifying a content does not make sense. So I was guided to pass ids on the Uri, hence the use of the "FromUri" attribute:
// DELETE: api/ProductionOrders/5
[HttpDelete("ProductionOrders")]
public IActionResult DeleteProductionOrder([System.Web.Http.FromUri]int[] ids)
{
//code
}
If this is a reasonable approach, is there a better way to build this Uri from the client-side? Imagine instead of an array of ints I had a complex type. How can I serialized this and put into the Uri?
For this example I end up building up a URI like this:
http://localhost:51081/api/ProductionOrders?ids=25563&ids=25533
Personally, if I have to pass a List or a complex type I would map values from the Body via JSON. The DELETE allow using body. And then just decorate your param with [FromBody] attribute.
Despite some recommendations not to use the message body for DELETE requests, this approach may be appropriate in certain use cases.
This allows better extensibility in case you need to change how the data is coming.
In your case with ids I’d create new class like this:
public class RequestEntity {
[JsonPropertyName("Ids")]
public List<int> Ids { get; set; }
}
And then when calling this method, send the Body along with the request.
{
"Ids": [25392, 254839, 25563]
}
In a future you can pass complex objects just by changing what is send to server and implement complex logic.
I have an endpoint that has a parameter that type of integer array.I want send some value from body as a json string.When I tried it , I was getting null value from parameter so I tried to send integer array from url but happen problem about of url length so I want to know that is possible to send it from request body or how to fix url length problem for 5.000 item
request body that I tried
{
"Ids": [349]
}
endpoint function
[HttpGet]
public void GetModels([FromBody]List<int> Ids)
{
}
First, in general including a body in a GET request is often not considered very RESTful. It is no longer specifically "banned" by RFC, but it is not typical. That said, you can make this work in ASP.Net Core using the [FromBody] attribute.
The issue has to do with how you are formatting your JSON body. Using the signature for GetModels that you have listed above, the JSON body doesn't match the parameters. Your JSON represents a top-level object with a property Ids that is an array of int, not just an array of it (or List).
If you want to use public void GetModels([FromBody]List<int> Ids) then your JSON body should simply be an array (e.g. [349,350,351]) and nothing else (no brackets, no "Ids" property name).
If you want to use the JSON body you list above, then you need another class to use for model binding, a DTO. That DTO would look something like:
public class IdDto
{
public List<int> Ids { get; set; }
}
and then your GetModels method would look like:
[HttpGet]
public void GetModels([FromBody] IdDto idDto)
{
var myIds = idDto.Ids;
}
Lastly, be sure that your GET request has a Content-Type set to application/json or ASP.Net will return a 415 "Unsupported Media Type".
I'm trying to figure out whats the best way to have multiple Get actions in a REST controller.
I would like to do something like this:
Get By Id:
public ResponseType Get(Guid id)
{
// implementation
}
Get By Enum Type:
public ResponseType Get(EnumType type)
{
// implementation
}
Get By Other Enum Type:
public ResponseType Get(OtherEnumType otherType)
{
// implementation
}
etc..
Now when I do something like that, I get the next error message:
Multiple actions were found that match the request
I understand why I get the message and I was thinking how is the best way to do something like that (I want to stick with REST).
I know I can add a route like this:
routeTemplate: "api/{controller}/{action}/{id}"
But then I would need to change the action names and the urls - And this seems like a workaround when we are talking about rest.
Another thing I thought was to create multiple controllers with one Get - But that seems even wronger.
The third workaround was to handle one Get action with an input param that will have the state:
public ResponseType Get(ReqeustObj obj)
{
switch(obj.RequestType)
{
case RequestType.GetById:
// etc...
}
}
Anyway, I would like to know whats the best way to do something like that in REST (WebApi).
As you now, when Web API needs to choose an action, if you don't specify the action name in the route, it looks for actions whose name starts with the method name, GET in this case. So in your case, it will find multiple methods.
But it also try to match the parameters. So, if you include the parameters as part of the url (route parameters) or the query string, the action selector will be able to choose one of the available methods.
If you don't specify a parameter or specify the id in the url (or even in the query string) it should invoke the first overload. If you add the parameter name of the second action in the query string like this: ?type=VALUE it should choose the corresponding overload, and so on.
The question is that the parameter names must be different, or it will not be able to choose one or the other among all the overloads.
For example, if you use the urls in the comments in your browser, you'll see how the right method is chosen:
public class TestController : ApiController
{
// GET api/Test
public string Get()
{
return "without params";
}
// GET api/Test/5
public string Get(int id)
{
return "id";
}
// GET api/Test?key=5
public string Get(string key)
{
return "Key";
}
// GET api/Test?id2=5
public string Get2(int id2)
{
return "id2";
}
}
NOTE: you can also use route constraints to invoke differet methods without using query string parameters, but defining different route parameter names with different constraints. For example you could add a constraint for id accepting only numbers "\d+" and then a second route which accepts "key" for all other cases. In this way you can avoid using the query string
I have a big set of classes (like more that 100) and they are all extend from some abstract class, let's call it ParentClass. Let's call child classes ChildA,ChildB, etc. How can I register custom deserializer for all children and get class type inside my Deserializer?
I tried:
module.addDeserializer(ParentClass.class, new MyObjectDeserializer());
but it does not work.
I want to skip doing (what is working):
module.addDeserializer(ChildA.class, new MyObjectDeserializer(ChildA.class));
module.addDeserializer(ChildB.class, new MyObjectDeserializer(ChildB.class));
module.addDeserializer(ChildC.class, new MyObjectDeserializer(ChildC.class));
//etc......
Class type should be known, as I am use Jackson for spring #RequestBody method, what have defined class name there.
Any ideas how this can be done?
As far as I know, I don't think there is a mechanism in jackson that will address your exact needs.
However, there are a couple alternatives you can try.
Deserializing polymorphic types with Jackson describes one such alternative, however, you would still need to explicitly define all of the supported subtypes.
Another alternative that would not require you to explicitly define deserialization relationships would be to change your class hierarchy from one of inheritance to that of a container.
For example, converting your abstract parent class to a container like so:
public class DataContainer<T> {
String commonString;
Integer commonInteger;
T subData;
}
Would allow you to simply define in your controller input function as
public String controllerFunction(DataContainer<ClassA> classA);
without a need to define all these subclass deserializations.
Late to the party but I had a similar problem which I solved by registering a custom Deserializers to my SimpleModule. The code is in Kotlin but it should be easy to port it to Java.
The class itself:
class UseBaseClassSimpleDeserializers(
private val baseClass: Class<*>,
private val baseClassDeserializer: JsonDeserializer<*>
) : SimpleDeserializers() {
#Throws(JsonMappingException::class)
override fun findBeanDeserializer(
type: JavaType?,
config: DeserializationConfig?,
beanDesc: BeanDescription?
): JsonDeserializer<*>? {
val beanDeserializer = super.findBeanDeserializer(type, config, beanDesc)
return if (beanDeserializer == null && baseClass.isAssignableFrom(type!!.rawClass)) {
baseClassDeserializer
} else {
beanDeserializer
}
}
}
How to register the custom Deserializers class to a SimpleModule:
val simpleModule = SimpleModule()
simpleModule.setDeserializers(UseBaseClassSimpleDeserializers(ParentClass::class.java, ParentClassDeserializer()))
What I'd like to do is something like the following:
FooClass.prototype.method = function():String
{
return "Something";
}
var foo:FooClass = new FooClass();
foo.method();
Which is to say, I'd like to extend a generated class with a single method, not via inheritance but via the prototype.
The class is generated from a WSDL, it's not a dynamic class, and I don't want to touch the generated code because it will be overwritten anyway.
Long story short, I'd like to have the moral equivalent of C# 3:s Extension Methods for AS3.
Edit: I accepted aib's answer, because it fits what I was asking best -- although upon further reflection it doesn't really solve my problem, but that's my fault for asking the wrong question. :) Also, upmods for the good suggestions.
Yes, such a thing is possible.
In fact, your example is very close to the solution.
Try
foo["method"]();
instead of
foo.method();
#Theo: How would you explain the following working in 3.0.0.477 with the default flex-config.xml (<strict>true</strict>) and even a -compiler.strict parameter passed to mxmlc?
Foo.as:
package
{
public class Foo
{
public var foo:String;
public function Foo()
{
foo = "foo!";
}
}
}
footest.as:
package
{
import flash.display.Sprite;
public class footest extends Sprite
{
public function footest()
{
Foo.prototype.method = function():String
{
return "Something";
}
var foo:Foo = new Foo();
trace(foo["method"]());
}
}
}
Note that the OP said inheritance was unacceptable, as was modifying the generated code. (If that weren't the case, adding "dynamic" to the class definition would probably be the easiest solution.)
Depending on how many methods your class has, this may work:
Actual Class:
public class SampleClass
{
public function SampleClass()
{
}
public function method1():void {
Alert.show("Hi");
}
Quick Wrapper:
var actualClass:SampleClass = new SampleClass();
var QuickWrapper:Object = {
ref: actualClass,
method1: function():void {
this.ref.method1();
},
method2: function():void {
Alert.show("Hello!");
}
};
QuickWrapper.method1();
QuickWrapper.method2();
#aib is unfortunately incorrect. Assuming strict mode (the default compiler mode) it is not possible to modify the prototype of non-dynamic class types in ActionScript 3. I'm not even sure that it's possible in non-strict mode.
Is wrapping an option? Basically you create a class that takes one of the objects you get from the web service and just forwards all method calls to that, but also has methods of its own:
public class FooWrapper extends Foo {
private var wrappedFoo : Foo;
public function FooWrapper( foo : Foo ) {
wrappedFoo = foo;
}
override public function methodFromFoo( ) : void {
wrappedFoo.methodFromFoo();
}
override public function anotherMethodFromFoo( ) : void {
wrappedFoo.anotherMethodFromFoo();
}
public function newMethodNotOnFoo( ) : String {
return "Hello world!"
}
}
When you want to work with a Foo, but also have the extra method you need you wrap the Foo instance in a FooWrapper and work with that object instead.
It's not the most convenient solution, there's a lot of typing and if the generated code changes you have to change the FooWrapper class by hand, but unless you can modify the generated code either to include the method you want or to make the class dynamic I don't see how it can be done.
Another solution is to add a step to your build process that modifies the source of the generated classes. I assume that you already have a step that generates the code from a WSDL, so what you could do is to add a step after that that inserts the methods you need.
Monkey patching is an (inelegant) option.
For example, suppose you don't like the fact that Flex 3 SpriteAsset.as returns a default border metrics of [7,7,7,7] (unlike flex 2). To fix this, you can:
Create a copy of SpriteAsset.as and add it to your project at /mx/core/SpriteAsset.as
Edit your local copy to fix any problems you find
Run your ap
Google "flex monkey patch" for more examples and instructions.