ASP.NET Web API possible deserialization issue while using flurl - c#

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.

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.

.NET C# retrieving data from Firebase

I'm facing some problems while retrieving data to my .net app from database hosted on Firebase. While debugging I noticed that response contains [{"Description":"desccc","Id":2},{"Description":"asdfasdf","Id":1}] and this is the only record in my db so I think for this moment everything is ok. Unfortunatelly, when trying to put this data into result it throws error like this:
{System.MissingMethodException: No parameterless constructor defined for this object. at System.Activator.CreateInstanceT at RestSharp.Deserializers.JsonDeserializer.Deserialize[T](IRestResponse response) at Rate_Your_Game.Controllers.GameController.GetGames() in PATH/Rate Your Game\Controllers\GameController.cs:line 49}
[HttpGet("[action]")]
public async Task<Game[]> GetGames()
{
try
{
client = new FireSharp.FirebaseClient(config);
FirebaseResponse response = await client.GetTaskAsync("Games/");
Game[] result = response.ResultAs<Game[]>();
return result;
}
catch (Exception e)
{
throw e;
}
}
This is my Game class
public class Game
{
public Game() {}
public int Id { get; set; }
public string Description{ get; set; }
}
The Game class needs to have parameterless constructor.
public class Game {
public Game(){
}
....
}

How to properly implement Xamarin NetworkServiceDiscovery via DependencyService?

I've got a Xamarin Cross-Platform App and want to use Android's NetworkServiceDiscovery API.
I tried to implement it according to https://developer.android.com/training/connect-devices-wirelessly/nsd.html
Now, I'm not sure if I did everything right, for example: The android documentation wants you to create a RegistrationListener like this:
Android:
public void initializeRegistrationListener() {
mRegistrationListener = new NsdManager.RegistrationListener() {
#Override
public void onServiceRegistered(NsdServiceInfo NsdServiceInfo) {
// Save the service name. Android may have changed it in order to
// resolve a conflict, so update the name you initially requested
// with the name Android actually used.
mServiceName = NsdServiceInfo.getServiceName();
}
#Override
public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
// Registration failed! Put debugging code here to determine why.
}
#Override
public void onServiceUnregistered(NsdServiceInfo arg0) {
// Service has been unregistered. This only happens when you call
// NsdManager.unregisterService() and pass in this listener.
}
#Override
public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
// Unregistration failed. Put debugging code here to determine why.
}
};
}
And I rebuilt it like this in C#:
public class RegistrationListener : NsdManager.IRegistrationListener
{
public string serviceName;
public void Dispose()
{
throw new NotImplementedException();
}
public IntPtr Handle { get; }
public void OnRegistrationFailed(NsdServiceInfo serviceInfo, NsdFailure errorCode)
{
// Registration failed! Put debugging code here to determine why.
}
public void OnServiceRegistered(NsdServiceInfo serviceInfo)
{
// Save the service name. Android may have changed it in order to
// resolve a conflict, so update the name you initially requested
// with the name Android actually used.
serviceName = serviceInfo.ServiceName;
}
public void OnServiceUnregistered(NsdServiceInfo serviceInfo)
{
// Service has been unregistered. This only happens when you call
// NsdManager.unregisterService() and pass in this listener.
}
public void OnUnregistrationFailed(NsdServiceInfo serviceInfo, NsdFailure errorCode)
{
// Unregistration failed. Put debugging code here to determine why.
}
}
I implemented the ResolveListener and DiscoveryListener in the same way.
Then I made a Helper Class with the functions I want to call via DependencyServices:
public class NsdHelper
{
public static readonly string SERVICE_TYPE = "chatTest._tcp";
public DiscoveryListener discoveryListener;
public NsdManager nsdManager;
public NsdServiceInfo nsdServiceInfo;
public RegistrationListener registrationListener;
public ResolveListener resolveListener;
public string SERVICE_NAME { get; set; }
public void InitializeNsd()
{
resolveListener = new ResolveListener();
discoveryListener = new DiscoveryListener();
registrationListener = new RegistrationListener();
resolveListener.ServiceName = SERVICE_NAME;
resolveListener.ServiceInfo = nsdServiceInfo;
discoveryListener.resolveListener = resolveListener;
discoveryListener.nsdManager = nsdManager;
}
public void RegisterService(string sessionName)
{
SERVICE_NAME = sessionName;
// Create the NsdServiceInfo object, and populate it.
nsdServiceInfo = new NsdServiceInfo
{
ServiceName = sessionName,
ServiceType = SERVICE_TYPE,
Port = GenerateFreePort()
};
InitializeNsd();
// The name is subject to change based on conflicts
// with other services advertised on the same network.
nsdManager = (NsdManager) Application.Context.GetSystemService(Context.NsdService);
nsdManager.RegisterService(
nsdServiceInfo, NsdProtocol.DnsSd, registrationListener);
}
private int GenerateFreePort()
{
//setting the ServerSocket to 0 will generate the next free port
var serverSocket = new ServerSocket(0);
return serverSocket.LocalPort;
}
public void DiscoverServices()
{
nsdManager.DiscoverServices(
SERVICE_TYPE, NsdProtocol.DnsSd, discoveryListener);
}
public void StopDiscovery()
{
nsdManager.StopServiceDiscovery(discoveryListener);
}
public NsdServiceInfo GetChosenServiceInfo()
{
return nsdServiceInfo;
}
public void TearDown()
{
nsdManager.UnregisterService(registrationListener);
}
}
And now when I call RegisterService I get the following Error:
I don't know where exactly I've gone wrong! The errors I get while debugging Xamarin Apps also don't help much :(
Inherit your RegistrationListener subclass from Java.Lang.Object
Remove the Handle property and the Dispose methods as those are implemented in the Java.Lang.Object.
public class RegistrationListener : Java.Lang.Object, NsdManager.IRegistrationListener
{
~~~
}
Once you do that a ACW (Android Callable Wrapper) that will be generated to bind your C# implementation so it can be instanced from Java VM.

Serializing Model using NewtonSoft in WPF Application

I am trying to serialize my model each second and push it to a server. I have set up a periodic task which executes each second. I call SendNewMessage to execute the push.
The first method call to SendNewMessage() which is called from the constructor runs fine with no exceptions or issues.
When the async task tries to call the SendNewMessage I get an exception and my application shuts down. It is the NewtonSoft code:
String PushModelToServer = JsonConvert.SerializeObject(this, jss); Which fails
Managed Debugging Assistant 'FatalExecutionEngineError' has detected a problem in
'C:\Users\snovva\Source\Workspaces\HMI\HMI.ViSoft\bin\x86\Debug\HMI.ViSoft.vshost.exe'.
Additional information: The runtime has encountered a fatal error. The address of the error was at 0x71041771, on thread 0x2788. The error code is 0xc0000005. This error may be a bug in the CLR or in the unsafe or non-verifiable portions of user code. Common sources of this bug include user marshaling errors for COM-interop or PInvoke, which may corrupt the stack.
public class Model : ModelBase
{
public Model ()
{
PeriodicTask.Run(() =>
{
SendNewMessage();
},
TimeSpan.FromSeconds(1));
SendNewMessage();
}
public void SendNewMessage()
{
// Send the message
JsonSerializerSettings jss = new JsonSerializerSettings();
jss.Formatting = Newtonsoft.Json.Formatting.Indented;
String PushModelToServer = JsonConvert.SerializeObject(this, jss);
sendMessage(System.Text.Encoding.Unicode.GetBytes(PushModelToServer));
}
}
public class PeriodicTask
{
public static async Task Run(Action action, TimeSpan period, CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
await Task.Delay(period, cancellationToken);
if (!cancellationToken.IsCancellationRequested)
action();
}
}
public static Task Run(Action action, TimeSpan period)
{
return Run(action, period, CancellationToken.None);
}
}
More Info As requested:
The call on line 10 in the constructor runs. The serialization works the first time. Since the data in the model is changing I am pushing this model every second to update server. It is the async call which fails. As time passes the data in the model will change.
You can use [IgnoreDataMember] to avoid serializing properties that should not be included.
The code below works in my application, and should hopefully help you arrive at a solution for your app.
I am hoping that the code you show above is a snippet of your real code because there are some potential issues with the 1 second timer, re-entrancy, etc. Instead of doing this timer in the Model constructor, consider moving it to another function/class and setting up the timer/calls from an additional call you setup later...again, just some suggestions on arriving at a good pattern. Do more research here...
Here is how I get my data, what you want in your PushModelToServer:
public class BackupData
{
public List<Vehicles> Vehicles { get; private set; }
public List<FuelStops> FuelStops { get; private set; }
public BackupData(List<Vehicles> vehicles, List<FuelStops> fuelStops)
{
Vehicles = vehicles;
FuelStops = fuelStops;
}
public string ToJson(Formatting formatting = Formatting.None)
{
var json = JsonConvert.SerializeObject(this, formatting);
return json;
}
public static BackupData FromJson(string jsonBackupData)
{
var data = JsonConvert.DeserializeObject<BackupData>(jsonBackupData);
return data;
}
}
Here is a snippet of one of my classes:
[DebuggerDisplay("{VehicleName}")]
public class Vehicles : IComparable<Vehicles>, INotifyPropertyChanged
{
private string id;
public string Id
{
get { return id; }
set
{
if (id != value) { id = value; NotifyPropertyChanged(); }
}
}
private string vehicleName;
public string VehicleName
{
get { return vehicleName; }
set
{
if (vehicleName != value) { vehicleName = value; NotifyPropertyChanged(); }
}
}
public override string ToString()
{
return VehicleName;
}
[IgnoreDataMember]
public UpdateState UpdateState { get; set; }
....
And here is how I get the data so I can use it anywhere I want:
#if WINDOWS_PHONE_APP
private void OnExecuteBackup(SettingsPage obj)
{
#else
private async Task<bool> OnExecuteBackup(SettingsPage obj)
{
#endif
var backupData = App.JournalModel.GetBackupData().ToJson(Formatting.Indented);
...
await SaveBackupFile(file, backupData);
...
public class JournalModel
{
...
public BackupData GetBackupData()
{
var data = new BackupData(Vehicles.ToList(), FuelStops.ToList());
return data;
}
...
Good luck with your project.
Well there must be something the the class You're trying to serialize, that makes the serializer go crazy. Maybe instead of serializing 'this' You should try serializing an actual 'DataObject' - something that can be serialized, and doesn't contain references to Timers, tasks, ect.. ?

Why does my ServiceStack service throw an exception?

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

Categories