I have a problem with an XML response to a call to the Web API.
Specifically, I have a function "GetValue" call that when I should return in XML format based to the id or class "Cellulare" or class "Televisore".
The problem is that if I make a request from browser gives me the following error:
<Message>An error has occurred.</Message>
<ExceptionMessage>
The 'ObjectContent`1' type failed to serialize the response body for content type 'application/xml; charset=utf-8'.
</ExceptionMessage>
This is the example:
Public Class Cellulare
Public Property Colore As String
Public Property SistemaOperativo As String
End Class
Public Class Televisore
Public Property Colore As String
Public Property Marca As String
End Class
Public Function GetValue(ByVal id As Integer) // ' As Cellulare
If Id = 1 Then
Dim MyTelevisore As New Televisore
MyTelevisore.Colore = "grigio"
MyTelevisore.Marca = "lg"
Return MyTelevisore
Else
Dim MyCellulare As New Cellulare
MyCellulare.Colore = "nero"
MyCellulare.SistemaOperativo = "android"
Return MyCellulare
End If
End Function
Can anyone help me to solve this problem???
Thank in advance
greetings
Donato
I think your approach is wrong.
You have simple objects to return, that can be handled easily by the default serializers webapi has to offer.
Your returned object type should be IHttpActionResult (webapi2) or HttpResponseMessage.
I would NOT go for what #Frank Witte suggested, cause returning the object itself is bad practice. Specifically here you can just return a generic object through IHttpActionResult / HttpResponseMessage.
You should do something like:
Public Function GetValue(ByVal id As Integer) As IHttpActionResult
If Id = 1 Then
Dim MyTelevisore As New Televisore
MyTelevisore.Colore = "grigio"
MyTelevisore.Marca = "lg"
Return Ok(MyTelevisore)
Else
Dim MyCellulare As New Cellulare
MyCellulare.Colore = "nero"
MyCellulare.SistemaOperativo = "android"
Return Ok(MyCellulare)
End If
End Function
It throws the error because you do not supply any return type to your GetValue function. You commented that out.
As I can tell from your code you are returning a different type of object depending on the id you supply to the GetValue call. I do not know the complete context of what you are trying to do, but from what I can see it would make more sense to have a different controller, or route at least, for the different types of object:
/api/cellulare/<id>
Would map to a controller CellulareController.
/api/televisore/<id>
Would map to a controller TelevisoreController. Each with their own Get(), Post() and Delete() methods if you will.
Hope this helps.
Related
Recently I've been following some WebApi2 tutorials. I have a situation whereby if a requested GET operation returns data outside of the user's remit, then I need to return a Forbidden code.
Imports System.Net
Imports System.Net.Http
Imports System.Web.Http
Namespace Controllers
Public Class MyController
Inherits ApiController
<Route("Records/{id}")>
Public Function [Get](id As Int32) As IHttpActionResult
If Not Remit.IsWithinRemit(id) Then
Return Request.CreateErrorResponse(HttpStatusCode.Forbidden, "This data is not within your remit")
Else
Dim r As New CustomObject(id)
Return Ok(r)
End If
End Function
End Class
End Namespace
Unfortunately, although the Ok(r) part works okay, CreateErrorResponse throws an InvalidCastException:
Unable to cast object of type 'System.Net.Http.HttpResponseMessage' to type 'System.Web.Http.IHttpActionResult'.
I know why the error is happening, but am unsure of the correct approach of how to fix it.
In other threads, people advise that CreateErrorResponse() is the best approach for WebApi2, but VS creates it's sample GET request returning IHttpActionResult. Its like stuff doesn't seem to fit together for us newbies at the moment...
No, it isn't obvious, but you can get what you want (error code plus message) AND return it from a method of type IHttpActionResult. No need to change the return type or go without error messages.
This is the helper class:
public class ErrorResult : IHttpActionResult
{
private HttpRequestMessage Request { get; }
private HttpStatusCode statusCode;
private string message;
public ErrorResult(HttpRequestMessage request, HttpStatusCode statusCode, string message)
{
this.Request = request;
this.statusCode = statusCode;
this.message = message;
}
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
return Task.FromResult(Request.CreateErrorResponse(statusCode, message));
}
}
and you can call it like this:
public IHttpActionResult MyMethod()
{
MyServiceLayer myServiceLayer = new MyServiceLayer();
MyType myvar;
if (MyServiceLayer.EverythingIsOK(ref myvar))
return Ok(myvar);
else
return new ErrorResult(Request, HttpStatusCode.SomeErrorCode, "Something Is Wrong");
}
try this
Change your Get method to return "HttpResponseMessage"
<Route("Records/{id}")>
Public Function [Get](id As Int32) As HttpResponseMessage
If Not Remit.IsWithinRemit(id) Then
Return Request.CreateResponse(HttpStatusCode.Forbidden, "This data is not within your remit")
Else
Dim r As New CustomObject(id)
Return Request.CreateResponse(HttpStatusCode.OK, r)
End If
End Function
Check below link
http://www.asp.net/web-api/overview/web-api-routing-and-actions/action-results
I found an alternative possible solution (there may be better but this one works and is simple). It returns
403 Forbidden
but with no content:
<Route("Records/{id}")>
Public Function [Get](id As Int32) As IHttpActionResult
If Not Remit.IsWithinRemit(id) Then
Return New Results.StatusCodeResult(HttpStatusCode.Forbidden, Request)
Else
Dim r As New CustomObject(id)
Return Ok(r)
End If
End Function
Because HttpResponseMessage comes from the same namespace, and also allows you to return custom error messages in addition to a HTTP status code, that option is more suitable to use in most cases.
I guess IHttpActionResult is for basic status code returns with no frills. I posted this alongside the above answer to give new coders visibility of both options.
I encountered the same error using .NET Framework 4.7.2. Rather than changing the return type** from IHttpActionResult, I corrected the bug by wrapping myHttpResponseMessage object in a ResponseMessageResult like this: -
return new ResponseMessageResult(myHttpResponseMessage);
** it was a single, custom case amongst a set of straightforward IHttpActionResult cases in a switch block
I'm trying to pass down parameters to my Action.
There are several parameters that I need to pass down.
When debugging, I found that the simple types of parameters got their values, whereas my own class parameters is null.
return RedirectToAction("Histories", new {MyUser = user, sortOrder = "name_desc" });
And here is the Action method:
public ActionResult Histories(ApplicationUser MyUser, string sortOrder, int? page)
I did a research and found , it seems that only objects which can be serialized can be passed down.
So I simply added an annotation [Serializable] on my ApplicationUser class, and it doesn't work.
So I'm wondering what's the best practice to pass down my objects?
I certainly know I can put the MyUser into Session["CurrentUser"], but I just don't like this old fashion.
Thank you.
You have not passed int? page value, it should be like this
return RedirectToAction("Histories", new {MyUser = user,
sortOrder = "name_desc",
page =1 });
or you need to use default parameter value like this
public ActionResult Histories(ApplicationUser MyUser,
string sortOrder,
int? page = 1)
I am currently working on the return class. The problem is I want to show the certain member only when some of the condition meet. Below is my code. I only want to show ResponseMsg member when the ResponseCode is 99 otherwise it will be hidden.
Public Class LoginResponse
Public Property TerminalID As String
Public Property ReaderID As String
Public Property TransRef As String
Public Property TransDateTime As String
Public Property Timeout As Integer
Public Property ResponseCode As String
Public Property ResponseMsg As String
Public Property Cryptogram As String
End Class
You can't that I know of. But you can do something like this:
Public Property ResponseMsg
Get
If ResponseCode <> SomeCodeValue
Return _responseCode
Else
Return Nothing
End if
End Get
End Property
You might want to think about making a specialized class.
Let's say you have your basic LoginResponse
Public Class LoginResponse
Public Property TerminalID As String
Public Property ReaderID As String
Public Property TransRef As String
Public Property TransDateTime As String
Public Property Timeout As Integer
Public Property ResponseCode As String
' Note: no ResponseMsg here
Public Property Cryptogram As String
End Class
Then you'd have an extended response class inheriting your basic LoginResponse:
Public Class LoginResponseEx : Inherits LoginResponse
Public Property ResponseMsg As String
End Class
Then where ever you create those LoginResponse objects, you just create one of the apropriate.
Let's say you have a GetResponse() procedure like:
Public Function GetResponse() As LoginResponse
Dim result As LoginResponse = Nothing
Dim code As Integer = GetSomeCode()
' ... get the other properties
' Say you have a const or something with the appropriate code: SPECIAL_CODE
If code = SPECIAL_CODE Then
Dim msg As String = GetSomeMessage()
result = New LoginResponseEx(..., code, msg, ...) ' have a special Response
Else
result = New LoginResponse(..., code, ...) ' have a normal Response
End If
Return result
End Function
Finally when checking the response you just check whether you have a special value in ResponseCode and cast the object respectivly.
'...
Dim resp as LoginResponse = GetResponse()
If resp.ResponseCode = SPECIAL_CODE Then
Dim respx as LoginResponseEx = CType(resp, LoginResponseEx)
Console.WriteLine("ResponseMessage was: " & respx.ResponseMsg
Else
Console.WriteLine("No ResponseMessage")
End If
'...
This way you have your basic LoginResponse with the ResponseMsg hidden in the special class ResponseLoginEx
Note when you do this you should think about how you implement virtual classes. e.g. the fields might have to be declared as Protected instead of Private, though i'm sure you'll do fine.
This also works with Serializable classes, of course.
We are developing a webservice for a client. We are not supose to throw SoapExceptions, so instead, we catch every exception server side, and return a custom Exception class.
Public Class Order
...
End Class
Public Class MyException
...
End Class
And then in my webservice a function (webmethod):
Public Function GetOrder(ByVal id As Integer) As Object
Try
...
Return New Order()
Catch ex As Exception
Return New MyException(ex.Message)
End Try
End Function
The problem now is, that since my webmethod is returning the type [Object]. The wdsl that is generated does not contain the order, or the exception.
I can change the [Object] to [Order] Or [MyException], but only one of them is generated in the wsdl.
So does anybody have an idea of how i should handle this? I want both the MyException type and the Order type in my wsdl, but i just cant get it working.
Thank you all.
If your definition of MyException
Public Class MyException
inherits System.Exception
...
End Class
then you shouldn't need to return the Custom Exception just throw it.
then you can define
Public Function GetOrder(ByVal id As Integer) As Order
Try
...
Return New Order()
Catch ex As Exception
Throw New MyException(ex.Message)
End Try
End Function
As I recall (and it's been a while) trying to return multiple objects from a web method can prove to be extremely troublesome
If you really want to return multiple objects, then maybe you should create a "wrapper" object, e.g something like this:
'please note: I don't normally use VB.NET, so there might be some errors
Public Class OrderResponse
Public Property Order() As Order
Get
Return m_Order
End Get
Set
m_Order = Value
End Set
End Property
Private m_Order As Order
Public Property Exception() As MyException
Get
Return m_Exception
End Get
Set
m_Exception = Value
End Set
End Property
Private m_Exception As MyException
End Class
Then change your method to return an instance of that class, with either the property Order or Exception set to the respective value:
Public Function GetOrder(ByVal id As Integer) As OrderResponse
...
End Function
I'm not sure if this is possible but I would like to associate a class name reference to a shared member method / property / variable. Consider:
Public Class UserParameters
Public Shared Reference As Object
Public Shared Function GetReference() As Object
Return Reference
End Function
End Class
In another part of the program I would like to simply call UserParameters and have it return Reference either by aliasing GetReference or the variable directly.
I am trying to emulate the Application, Request, or Session variable:
Session(0) = Session.Item(0)
Any suggestions would be greatly appreciated.
You can't return an instance member from a static method directly (the static method can't access instance members because it isn't instantiated with the rest of the class, only one copy of a static method exists).
If you need to setup a class in such a way that you can return an instance from a static method you would need to do something similar to the following:
Public Class SampleClass
Private Sub New()
'Do something here
End Sub
Public Shared Function GetSample() As SampleClass
Dim SampleClass As SampleClass
SampleClass = New SampleClass
SampleClass.Sample = "Test"
Return SampleClass
End Function
Private _SampleString As String
Public Property Sample As String
Get
Return _SampleString
End Get
Private Set(ByVal value As String)
_SampleString = value
End Set
End Property
End Class
Public Class SampleClass2
Public Sub New()
'Here you can access the sample class in the manner you expect
Dim Sample As SampleClass = SampleClass.GetSample
'This would output "Test"
Debug.Fail(Sample.Sample)
End Sub
End Class
This method is used in various places in the CLR. Such as the System.Net.WebRequest class. where it is instantiated in this manner in usage:
' Create a request for the URL.
Dim request As WebRequest = WebRequest.Create("http://www.contoso.com/default.html")