How can I deserializing JSON while returns different type? - asp.net-core

I post some data to the remote server. When the data run succeeded, it returns:
{"access_token":"sd234sd234sdf324","expires_in":7200}
When it failed, it returns:
{"errcode":40013,"errmsg":"invalid appid"}
Here is my code:
HttpClient HC = new HttpClient();
HttpResponseMessage HRM = await HC.PostAsync("https://www.microsoft/callback/aaa/), null);
string Content = await HRM.Content.ReadAsStringAsync();
Models.SuccessModel SM=(Models.SuccessModel)JsonSerializer.Deserialize(Content, typeof(Models.SuccessModel));
The last part for converting JSON to the class, I used the SuccessModel yet but if returns the failed JSON it will throw an error which Type is wrong.
I know what the error is. But how can I deal with this?
I want to get whether it is succeeded or failed and get the value of it.
Thank you.

Make another model for error as follows:
public class ErrorModel
{
public string errcode {get;set;}
public string errmsg {get;set;}
}
Then do as follows:
string response = await HRM.Content.ReadAsStringAsync();
if (response.Contains("access_token", StringComparison.OrdinalIgnoreCase))
{
Models.SuccessModel successModel =(Models.SuccessModel)JsonSerializer.Deserialize(response, typeof(Models.SuccessModel));
} else
{
ErrorModel erroModel = (Models.ErrorModel)JsonSerializer.Deserialize(response,typeof(Models.ErrorModel));
}

However, you can work this way
public class Model
{
public string access_token { get; set;}
public long expires_in { get; set;}
public int errcode { get; set;}
public string errmsg { get; set;}
}
So just get the response and check errcode when use it, no need to check when Deserialize

Related

Issue on signalR dotnet core

Issue
Scenario:
SignalR version 1.0.0 RC1 Final
DotNet Core 2.0
Tipical: User - Posts - Comments models.
Issue:
When I send a model through websocket fails silently (no message is send to clients). It works fine if I set to null navigation property:
_context.Posts.Add(model);
_context.SaveChanges();
model.User.Posts = null; // <- removing this line fails silently
_hub.Clients.All.SendAsync("AddAsync", model);
How can I diagnose what is happens? Someone knows what is the reason?
Some unnecesary code details
User.cs
public Guid Id { get; set; }
// ...
public virtual List<Post> Posts { get; set; } = new List<Post>();
Post.cs
public Guid Id { get; set; }
// ...
public virtual User User { get; set; }
PostsController.cs
private IHubContext<PostsHub> _hub;
private DatabaseContext _context;
public PostsController(IHubContext<PostsHub> hub)
{
_hub = hub;
}
// ...
[HttpPost]
public async Task<ActionResult> PostAsync([FromBody] Post model)
{
// ...
_context.Posts.Add(model);
_context.SaveChanges();
model.User.Posts = null;
_hub.Clients.All.SendAsync("AddAsync", model);
// ...
}
With json convert Serialize the model to json and deserialize it again as Post object just before sending it.
If there is an error it should popup there, because if there is a dependency loop json convert should throw exception

Client WebServiceException has ResponseStatus null without explicit ResponseStatus

I am quite new to ServiceStack, I am following the example at http://nilsnaegele.com/codeedge/servicestack1.html which I have been finding useful.
I read that explicit StatusResponse fields in DTO Response declarations were not required in the new API, but I dont appear to be getting the expected behaviour here.
Using ServiceStack 3.9.71.
I introduced an Exception in the EntryService post to get a feel for the client handling.
public object Post(Entry request)
{
if (request.Quantity == 3)
{
throw new WebException("post entry");
}
}
With
public class EntryResponse
{
public int Id { get; set; }
}
Then in the client side when posting an Entry handle the exception.
try
{
var entryRequest = new Entry {Quantity = quantity, EntryTime = DateTime.Now};
var response = client.Send(entryRequest);
Console.WriteLine("Response: {0}", response.Id);
}
catch (WebServiceException wse)
{
// At this point wse.ResponseStatus field is null.
}
I tested out explicitly adding the ResponseStatus field to EntryResponse and this produced the ResponseStatus filled in on the client with no change to the client code.
I then tried throwing an exception in StatusRequestService as follows to see if the second web service client request would behave the same way, and it appears it behaves differently.
public object Any(StatusRequest request)
{
if (request.Lever == 3)
{
throw new WebException("get status.");
}
}
With the following.
public class StatusResponse
{
public int Total { get; set; }
public int Goal { get; set; }
}
Then catching this in the client as per
try
{
var postResponse = client.Post<StatusResponse>("status", new StatusRequest { Date = DateTime.Now, Lever = 3 });
Console.WriteLine("{0} of {1} achieved", postResponse.Total, postResponse.Goal);
}
catch (WebServiceException wse)
{
// At this point wse.ResponseStatus field is valid and filled in.
}
If you want to use the {RequestDto}Response convention and also ensure a ResponseStatus is returned you have to opt-in and add it to the Response DTO, e.g:
public class StatusResponse
{
public int Total { get; set; }
public int Goal { get; set; }
public ResponseStatus ResponseStatus { get; set; }
}
This is because there is an explicit exception for Responses that follow the convention {RequestDto}Response naming convention:
If it exists:
The {RequestDto}Response is returned, regardless of the service method's response type. If the {RequestDto}Response DTO has a ResponseStatus property, it is populated otherwise no ResponseStatus will be returned. (If you have decorated the {ResponseDto}Response class and properties with [DataContract]/[DataMember] attributes, then ResponseStatus also needs to be decorated, to get populated).
Otherwise, if it doesn't:
A generic ErrorResponse gets returned with a populated ResponseStatus property.
The Service Clients transparently handles the different Error Response types, and for schema-less formats like JSON/JSV/etc there's no actual visible difference between returning a ResponseStatus in a custom or generic ErrorResponse - as they both output the same response on the wire.

Handle Conversion Error using Resource Files

I have Internationalized my MvC4 application.Inside model there is one property
public float Fuels{ get; set; }
When i typed string value inside textbox corresponding to this property,I got a validation error 'The value 'ff' is not valid for Fuels.'.But i want to handle it using resource file.If i have selected arabic then validation error should come in arabic..
I got required message using the following code
[Required(ErrorMessageResourceType = typeof(#Application.Resources.Admin.Country),
ErrorMessageResourceName = "FuelReq")]
I have tried the following way:-
public class FLoatAttribute : DataTypeAttribute
{
private const string defaultErrorMessage = "{0} is required.";
public FLoatAttribute()
: base(defaultErrorMessage)
{
}
public override string FormatErrorMessage(string name)
{
return string.Format(ErrorMessageString, name);
}
public override bool IsValid(object value)
{
float objFloat;
return float.TryParse(Convert.ToString(value), out objFloat);
}
}
and tried using regular expression inside model.But it didn't worked.
Pls help me.

Return Entity Framework objects over WCF

We have a problem concerning Entity Framework objects and sending them through WCF.
We have a database, and Entity Framework created classes from that database, a 'Wallet' class in this particular situation.
We try to transfer a Wallet using this code:
public Wallet getWallet()
{
Wallet w = new Wallet();
w.name = "myname";
w.walletID = 123;
return w;
}
We need to transfer that Wallet class, but it won't work, we always encounter the same exception:
"An error occurred while receiving the HTTP response to localhost:8860/ComplementaryCoins.svc. This could be due to the service endpoint binding not using the HTTP protocol. This could also be due to an HTTP request context being aborted by the server (possibly due to the service shutting down). See server logs for more details."
We searched on the internet, and there is a possibility that the error is due to the need of serialization of Entity Framework-objects.
We have absolutely no idea if this could be the case, and if this is the case, how to solve it.
Our DataContract looks like this (very simple):
[DataContract]
public partial class Wallet
{
[DataMember]
public int getwalletID { get { return walletID; } }
[DataMember]
public string getname { get { return name; } }
}
Does anyone ever encountered this problem?
EDIT: Our Entity Framework created class looks like this:
namespace ComplementaryCoins
{
using System;
using System.Collections.Generic;
public partial class Wallet
{
public Wallet()
{
this.Transaction = new HashSet<Transaction>();
this.Transaction1 = new HashSet<Transaction>();
this.User_Wallet = new HashSet<User_Wallet>();
this.Wallet_Item = new HashSet<Wallet_Item>();
}
public int walletID { get; set; }
public string name { get; set; }
public virtual ICollection<Transaction> Transaction { get; set; }
public virtual ICollection<Transaction> Transaction1 { get; set; }
public virtual ICollection<User_Wallet> User_Wallet { get; set; }
public virtual ICollection<Wallet_Item> Wallet_Item { get; set; }
}
}
Thanks for helping us.
I had the same problem some time ago and the solution for this was:
The entity framework was returning a serialized class instead of normal class.
eg. Wallet_asfawfklnaewfklawlfkawlfjlwfejlkef instead of Wallet
To solve that you can add this code:
base.Configuration.ProxyCreationEnabled = false;
in your Context file.
Since the context file is auto generated you can add it in the Context.tt
In the Context.tt file it can be added around lines 55-65:
<#=Accessibility.ForType(container)#> partial class <#=code.Escape(container)#> : DbContext
{
public <#=code.Escape(container)#>()
: base("name=<#=container.Name#>")
{
base.Configuration.ProxyCreationEnabled = false;
<#
if (!loader.IsLazyLoadingEnabled(container))
{
#>
this.Configuration.LazyLoadingEnabled = false;
<#
Try specifying a setter for the properties, something like this :
[DataContract]
public partial class Wallet
{
[DataMember]
public int getwalletID { get { return walletID; } set { } }
[DataMember]
public string getname { get { return name; } set { } }
}
If it still doesn't work, you may consider creating an intermediate POCO class for this purpose, and use mapper library like AutoMapper or ValueInjecter to transfer the data from the EF objects.
The POCO class should have same properties as your EF class :
[DataContract]
public class WalletDTO
{
[DataMember]
public int walletID { get; set; }
[DataMember]
public string name { get; set; }
}
And modify your method to return this class instead :
public WalletDTO getWallet()
{
Wallet w = new Wallet(); // or get it from db using EF
var dto = new WalletDTO();
//assuming we are using ValueInjecter, this code below will transfer all matched properties from w to dto
dto.InjectFrom(w);
return dto;
}
Are you trying to recieve a IEnumerable<Wallets>? If - yes, please modify your server class that returns the IEnumerable by adding .ToArray() method

toList() System.InvalidCastException was unhandled by user code

I have written a WCF service using LINQ to SQL (using the following article at codeporject). I am facing the invalid cast exception when i invoke the .ToList() method of an object after i have already made a wcf function call of the same service against the same database.
The exception is:
System.InvalidCastException was unhandled by user code
Message=Specified cast is not valid.
Source=System.Data
StackTrace:
at System.Data.SqlClient.SqlBuffer.get_Int64()
at System.Data.SqlClient.SqlDataReader.GetInt64(Int32 i)
at Read_Command(ObjectMaterializer`1 )
at System.Data.Linq.SqlClient.ObjectReaderCompiler.ObjectReader`2.MoveNext()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at SystemsManager.ACS.GetCommands(Int64 agentId) in E:\Projects\SystemsManager\AgentControlService\ACS.svc.cs:line 167
at SyncInvokeGetCommands(Object , Object[] , Object[] )
at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
InnerException:
The specific line i am having issue is with the ToList() method
public List<Command> GetCommands(long agentId)
{
var cmd = from command in db.Command where (command.AgentId == agentId) select command;
return cmd.ToList();
}
When debugging, the return statment throws exception. When view the value of cmd.ToList() in Quick Watch of VS 2010, the exception is shown.
Now the strangest thing is: Pressing "Re-Evaluate" button a couple of times changes the exception to required object list in Quick watch. Infact i have to press "Re-evaluate" at least three times.
I have generated client using svcutil tool after my most recent changes to the service/database.
I am calling the method using the following code from a windows service:
var agent = client.GetAgentByIpAddress(myIPAddress);
client.Close();
if (agent != null)
{
if (agent.AgentId != -1)
{
client = new ACSClient();
var command = client.GetCommands(agent.AgentId);
.....
Here is the model of Command in the interface of the wcf service.
[DataContract]
[Table(Name = "Command")]
public class Command
{
[DataMember, Column(IsPrimaryKey = true, Name = "Command_Id", AutoSync = AutoSync.OnInsert, IsDbGenerated = true, DbType = "Bigint NOT null identity")]
public long CommandId { get; set; }
[DataMember, Column(Name = "Agent_Id")]
public long AgentId { get; set; }
[DataMember, Column(Name = "Name")]
public string CommandName { get; set; }
[DataMember, Column(Name = "Paramters")]
public string CommandParamters { get; set; }
[DataMember, Column(Name = "Is_Fetched")]
public bool IsFectched { get; set; }
[DataMember, Column(Name = "Status")]
public long Status { get; set; }
[DataMember, Column(Name = "Response")]
public string Response { get; set; }
[DataMember, Column(Name = "Created")]
public DateTime Created { get; set; }
[DataMember, Column(Name = "Last_Modified")]
public DateTime LastModified { get; set; }
[DataMember, Column(Name = "Is_Enabled")]
public bool IsEnabled { get; set; }
}
Important thing is: My database file is located in AppData folder of the WCF service. I am using only one instance of db object (refer to 1st code block above) throughout my wcf service and i am wondering if this could be cause of the problem???
Also, i have called a couple of similar method of this very same wcf service from a desktop application but i have not faced any such issue.
Please help. if more details are needed, please state so.. The only thing that can come to mind is that perhaps the database is in use and when another connection is made to the database by the service, it fails. and retrying it a couple of times using the Quick Watch > Re-evaluate button displays the required values in the watch window without throwing any error.
Kindly help on this one. Quick responses are highly appreciated.
Thanks.
Steve
Never mind guys. I solved it.
For anyone else who is getting invalid cast exception, here is the solution.
The error only occurs when actual class model is different that the database.
If you have created the class model by hand coding it, the you must match each column name of the table to your corresponding class. LINQ to sql encounters error when it cannot convert a database type to .Net type and throws invalid cast exception.
So in most cases, either fixing the error manually in the model class or regenerating the class will solve the problem.