Why does my ServiceStack service throw an exception? - c#

I have constructed a simple Rest service using ServiceStack (which is brilliant), that returns a list of key value pairs.
My service looks like this:
public class ServiceListAll : RestServiceBase<ListAllResponse>
{
public override object OnGet(ListAllResponse request)
{
APIClient c = VenueServiceHelper.CheckAndGetClient(request.APIKey, VenueServiceHelper.Methods.ListDestinations);
if (c == null)
{
return null;
}
else
{
if ((RequestContext.AbsoluteUri.Contains("counties")))
{
return General.GetListOfCounties();
}
else if ((RequestContext.AbsoluteUri.Contains("destinations")))
{
return General.GetListOfDestinations();
}
else
{
return null;
}
}
}
}
my response looks like this:
public class ListAllResponse
{
public string County { get; set; }
public string Destination { get; set; }
public string APIKey { get; set; }
}
and I have mapped the rest URL as follows:
.Add<ListAllResponse>("/destinations")
.Add<ListAllResponse>("/counties")
when calling the service
http://localhost:5000/counties/?apikey=xxx&format=xml
I receive this exception (a breakpoint in the first line of the service is not hit):
NullReferenceException
Object reference not set to an instance of an object.
at ServiceStack.Text.XmlSerializer.SerializeToStream(Object obj, Stream stream) at ServiceStack.Common.Web.HttpResponseFilter.<GetStreamSerializer>b_3(IRequestContext r, Object o, Stream s) at ServiceStack.Common.Web.HttpResponseFilter.<>c_DisplayClass1.<GetResponseSerializer>b__0(IRequestContext httpReq, Object dto, IHttpResponse httpRes) at ServiceStack.WebHost.Endpoints.Extensions.HttpResponseExtensions.WriteToResponse(IHttpResponse response, Object result, ResponseSerializerDelegate defaultAction, IRequestContext serializerCtx, Byte[] bodyPrefix, Byte[] bodySuffix)
The exception is thrown regardless of whether I include any parameters in call or not. I have also created a number of other services along the same lines in the same project which work fine. Can anyone point me in the right direction as to what this means?

Your web service design is a little backwards, Your Request DTO should go on RestServiceBase<TRequest> not your response. And if you're creating a REST-ful service I recommend the name (i.e. Request DTO) of your service to be a noun, e.g. in this case maybe Codes.
Also I recommend having and using the same strong-typed Response for your service with the name following the convention of '{RequestDto}Response', e.g. CodesResponse.
Finally return an empty response instead of null so clients need only handle an empty result set not a null response.
Here's how I would re-write your service:
[RestService("/codes/{Type}")]
public class Codes {
public string APIKey { get; set; }
public string Type { get; set; }
}
public class CodesResponse {
public CodesResponse() {
Results = new List<string>();
}
public List<string> Results { get; set; }
}
public class CodesService : RestServiceBase<Codes>
{
public override object OnGet(Codes request)
{
APIClient c = VenueServiceHelper.CheckAndGetClient(request.APIKey,
VenueServiceHelper.Methods.ListDestinations);
var response = new CodesResponse();
if (c == null) return response;
if (request.Type == "counties")
response.Results = General.GetListOfCounties();
else if (request.Type == "destinations")
response.Results = General.GetListOfDestinations();
return response;
}
}
You can either use the [RestService] attribute or the following route (which does the same thing):
Routes.Add<Codes>("/codes/{Type}");
Which will allow you to call the service like so:
http://localhost:5000/codes/counties?apikey=xxx&format=xml

Related

C# Optional<TObject> as a return type?

Often i have a method where i want to return the error if something goes wrong, and instead of returning null, I want something less prone to errors at runtime and more easy to consume. Is there anything already done in .Net or maybe a nuget package?
Maybe have a constructor with optional parameters or object initializer would be enough?
This would have been the first approach but then every new Dto has to either have these Error property or inherit from a base class.
if (condition)
{
return new MyDto(null, error);
}
return new MyDto(someVariable, null);
So I've made this class to use a return type:
public class Optional<TObject> where TObject : class
{
public Optional(TObject? value)
{
Value = value;
}
public Optional(String error)
{
Error = error;
}
public TObject? Value { get; }
public String Error { get;} = String.Empty;
public Boolean IsError => !String.IsNullOrEmpty(Error);
}
I return it in the method:
if (condition)
{
return new Optional(error);
}
return new Optional(new MyDto(someVariable));
And then consume it like this:
var result = await myService.GetSomethingAsync();
if(result.IsError)
{
await DisplayAlert("error", result.Error, "Ok");
}
else
{
await DoSomethingElse(result.Value);
}
By creating a small class hierarchy, you could ensure that the Value property is only available when no error occurred
public abstract class Result
{
public virtual string Message => null;
public static Error Error(string message) => new Error(message);
public static Okay<T> Okay<T>(T value) where T : class => new Okay<T>(value);
}
public class Error : Result
{
public Error(string errorMessage) => Message = errorMessage;
override public string Message { get; }
}
public class Okay<T> : Result
where T : class
{
public Okay(T value) => Value = value;
public T Value { get; }
}
Usage
Result result = Result.Error("Something went wrong");
// OR
Result result = Result.Okay(new MyDto(someVariable));
if (result is Okay<MyDto> dtoResult) {
Console.WriteLine(dtoResult.Value);
} else {
Console.WriteLine(result.Message);
}
Or by using a recursive pattern, we can retrieve the value into a variable directly
if (result is Okay<MyDto> { Value: var dto }) {
Console.WriteLine(dto);
} else {
Console.WriteLine(result.Message);
}
Note that I have declared the Message property in the abstract base class Result, so that you don't have to cast to the Error type to get the message.
I used null as defualt value for the error message, as it allows us to write
Console.Writeline(result.Message ?? "okay");
This OneOf recommendation you got looks promising. I will personally have a look at it later.
What I do with my services is to standardize the result they return by using a SvcResult class or an inherited class.
Example:
public class SvcResult
{
public List<Error> Errors { get; } // Error is a class of my own. Add set; if deserialization is needed.
public bool Success { get; } // Add set; if deserialization is needed.
// Then parameterless constructor for a successful result.
// Then parameterized constructor to receive errors for a failed result.
}
That is the class for side-effect service calling. If The service returns data, I derive from the above to create DataSvcResult:
public class DataSvcResult<TResult> : SvcResult
{
public TResult Data { get; }
// Add constructor that receives TResult for a successful object result.
// Expose base class constructor that takes errors.
}
Basically that's what I do. But that OneOf thing, though. Looks super intersting.

ASP.NET Web API possible deserialization issue while using flurl

I have a ASP.NET(C#, .NET 4.6.1) Web-Api-GET function which returns a complex object instance and is of generic type. Here is the return type definition (Note that the classes are much expansive in reality).
public class FileProcessInstance
{
public FileProcessInstance()
{ }
//ID that identifies file by primary key of log table
public int FileLogID;
//File name without path as received
public string OriginialFileName;
//Path with file name where file can be physically accessed
public string FileSharePath;
}
public class CommonStatusPayload<T> : CommonStatus
{
public CommonStatusPayload() : base(false)
{
Payload = default(T);
}
public CommonStatusPayload(T payload, bool status)
: base(status)
{
Payload = payload;
}
public virtual T Payload { get; private set; }
}
public class CommonStatus
{
public CommonStatus() : this(false)
{
}
public CommonStatus(bool status)
{
Status = status;
}
public bool Status { get; set; }
}
Now my web api looks like this:
[HttpGet]
public CommonStatusPayload<List<FileProcessInstance>> GetFilesForProcessing()
{
List<FileProcessInstance> lst = new List<FileProcessInstance>() { new FileProcessInstance() { FileLogID = 1, FileSharePath = #"\\d\s", OriginialFileName = "d.txt" } };
CommonStatusPayload<List<FileProcessInstance>> cs = new CommonStatusPayload<List<FileProcessInstance>>(lst, true);
return cs;
}
The issue is, a call to this api from C# code would receive null as payload, while Postman request does receive proper payload.
Now my client code looks like this:
static void Main(string[] args)
{
var lst = GetFilesForProcessing();
}
private static List<FileProcessInstance> GetFilesForProcessing()
{
List<FileProcessInstance> lst = new List<FileProcessInstance>();
try
{
Task<CommonStatusPayload<List<FileProcessInstance>>> task = GetFilesForProcessingFromAPI();
task.Wait();
if (task.Result.Payload != null)
lst.AddRange(task.Result.Payload);
}
catch (Exception ex)
{
}
return lst;
}
private static async Task<CommonStatusPayload<List<FileProcessInstance>>> GetFilesForProcessingFromAPI()
{
return await "http://localhost:10748/api/values/GetFilesForProcessing".ToString()
.GetAsync().ReceiveJson<CommonStatusPayload<List<FileProcessInstance>>>();
}
I have observed that the return payload works if it were to be a a) list by itslef b) a local instance of CommonStatusPayload<List<FileProcessInstance>>. This makes me believe that there is a possible deserialization issue, when the result is handed over to C# code from web-api. A fiddler check for the same request turns out to be just fine, just that C# client would not receive proper result.
Any guess as to what could be the underlying reason for payload being null?
I found the root cause of this issue. The private setter for Payload within CommonStatusPayload class is causing the deserialization to fail. Although for the intended behavior, i wanted the payload to be set only via constructor/method always to be associated with a relative status, at-least this change allows me to continue.
I did find some other questions here, related to JSON.NET with protected setters having same issues.

How to manage two type of json in the same class?

I have this json structure:
[{"trace":{"details":{"date":"[28-02-2016 11:04:26.856573]","type":"[info]","message":"[system done.]"},"context":{"context":[[{"ID":"john dillinger"}]]}}},{"trace":{"details":{"date":"[28-02-2016 11:04:26.856728]","type":"[info]","message":"[trace done.]"},"context":{"context":[[{"ID":"john dillinger"}]]}}}]
I can deserialize it correctly using this class:
public class Trace
{
public TraceValue trace;
}
public class TraceValue
{
public Details details;
public Context context;
}
public class Details
{
public String date;
public String type;
public String message;
}
public class Context
{
public List<List<IdItem>> context;
}
public class IdItem
{
public String ID;
}
an example of deserialization:
var response = "json above";
var obj = JsonConvert.DeserializeObject<List<Trace>>(response);
now the problem is that sometimes the json is returned with this structure:
{
"success": false,
"message": "No content."
}
my code fall in error 'cause the structure is different. I tried to read the header but is returned as 200 'cause no error happean. So how can I recognize the different structure and avoid the json exception? This is the class to manage the different json structure:
public class RootObject
{
public bool success { get; set; }
public string message { get; set; }
}
I could do this in the exception but this isn't a good practice, there is another way?
In a case like yours, the better is to first obtain a JToken and then check if it has the message property and deserialize to the correct object:
var container = (JContainer)Newtonsoft.Json.JsonConvert.DeserializeObject(response);
var message = container["message"];
if(message == null)
{
var obj = container.ToObject<List<Trace>>();
//Do whatever you need to do with the object
}
else
{
var msg = container.ToObject<RootObject>();
//Do whatever you need to do with the object
}
Not a proper way but I have done this.
Convert the generated json object in to string. And edit the string to make the same format.
Than you can parse both string which are in same format

Accepting different types for WCF object parameter

I'd like to be able to accept all kind of parameters for a WCF call. The actual signature is something like this:
[DataContract]
public class Message
{
private Message() {}
public static Message Create(MessageTypeEnum type, params object[] parameters)
{
return new Message {MessageType = type, Parameters = parameters};
}
[DataMember]
public MessageTypeEnum MessageType { get; private set; }
[DataMember]
public object[] Parameters { get; private set; }
}
public void SendMessage(Message message)
{
var receivers = GetReceiversByMessageType(Message.MessageType);
foreach(var receiver in receivers)
{
var template = GetMessage(type, receiver.Locale)
var text = string.Format(template, receiver.Locale, Message.Parameters);
SendMessage(receiver.Address, text);
}
}
The message call works for simple types, like integers, dates and strings.
However, I'd like to be able to also send tuples and arrays of arrays.
(I'm actually using a different formatting method supporting this)
My WCF call throws (de)serialization exceptions. Is there a trick to allow for different types?
edit
Some context:
As WCF is used to communicate between our web servers and our business logic servers, this is kind of a requirement. There should always be a good reasons to deviate from standards, and I don't think a simple alerter qualifies.
In our actual solution, a seperate Message object is used. I can change both the client and the server side of how the message is serialized. I cannot change the message creation method, as is it is used at too many places.
This works:
var msg = Message.Create(MessageTypeEnum.InvalidName, "Petr");
Clients.MessageClient(c => c.SendMessage(msg));
this doesn't:
var msg = Message.Create(MessageTypeEnum.InvalidNames, new[] {"Petr", "Jann"};
Clients.MessageClient(c => c.SendMessage(msg));
Here's what I came up with to make the message serialize and deserialize. Note that the deserialized version has lost its complex types, and all collections have been converted to arrays. That's good enough for my purposes.
[DataContract]
public class Message
{
public static Message Create(MessageTypeEnum type, params object[] parameters)
{
return new Message {MessageType = type, Parameters = parameters};
}
[DataMember]
public MessageTypeEnum MessageType { get; set; }
public IList<object> Parameters { get; set; }
[DataMember]
public IList<string> SerializedParameters
{
get { return Parameters.Select(JsonConvert.SerializeObject).ToArray(); }
set { Parameters = value.Select(DeserializeObject).ToArray(); }
}
private object DeserializeObject(string json)
{
return ReplaceArrays(JsonConvert.DeserializeObject(json));
}
private object ReplaceArrays(object obj)
{
var dictionary = obj as IDictionary<string, JToken>;
if (dictionary != null) return dictionary.ToDictionary(kvp => kvp.Key, kvp => ReplaceArrays(kvp.Value));
var collection = obj as JArray;
if (collection != null) return collection.Cast<object>().Select(ReplaceArrays).ToArray();
var jValue = obj as JValue;
if (jValue != null) return jValue.Value;
return obj;
}
}
(...)
public void SendMessage(Message message)
{
var receivers = GetReceiversByMessageType(Message.MessageType);
foreach(var receiver in receivers)
{
var template = GetMessage(type, receiver.Locale)
var text = string.Format(template, receiver.Locale, Message.Parameters);
SendMessage(receiver.Address, text);
}
}

Asp.net method with generic parameter

I have a generic APIResponse<T> object that wraps the result of an API call:
public class APIError
{
public string ErrorMessage { get; set; }
}
public class APIResponse<T>
{
public T Result { get; set; }
public APIError Error { get; set; }
public bool HasError
{
get { return Error != null; }
}
}
I have a method that calls an API:
public APIResponse<string> GetUserName()
{
APIResponse<string> response = new APIResponse<string>();
try
{
// make http request
response.Result = httpResponse;
}
catch
{
response.Error = new APIError { ErrorMessage = "Some error occurred" };
}
return response;
}
// I call the method like this
APIResponse<string> userNameResponse = GetUserName();
// i need to handle the apiResponse
HandleAPIResponse(userNameResponse);
I want to create a generic method that inspects the APIResponse<T> object, and throws an exception if it has an error, but i can't make it work without specifying the result type:
public void HandleAPIResponse(APIResponse<T> apiResponse)
{
if (apiResponse.HasError)
throw new Exception(apiResponse.Error.ErrorMessage);
}
Can i make a method that accepts APIResponse<T> as parameter, but without specifying the type of T?
The method definition should be as follows:
public void HandleAPIResponse<T>(APIResponse<T> apiResponse)
{
if (apiResponse.HasError)
throw new Exception(apiResponse.Error.ErrorMessage);
}
Someone correct me if I am wrong but I don't think that will be possible as that will assume an Overloaded style type and would be referencing a different type.

Categories