I have the following problem: I have an IDto
interface and a Dto
base class implementing said interface.
The base class overrides an id
and a ManualId
which are defined in the HasId
base class.
Then I also have an AuthorDto
which inherits from the Dto
base class.
Now when I try to perform a http request (POST
method) to the service, the ManualId
does not get transferred to the service correctly even though the JSON string contains the correct ManualId
.
Please help.
My IDto interface:
public interface IDto : IHasId
{
IDto CloneData();
}
My dto base class:
public abstract class Dto : HasId, IDto
{
[DataMember]
public override long? Id { get; set; }
[DataMember]
public override Guid ManualId { get; protected set; } = Guid.NewGuid();
public abstract IDto CloneData();
protected bool Equals(Dto other)
{
return base.Equals(other) && Id == other.Id;
}
public override bool Equals(object obj)
{
if(ReferenceEquals(null, obj)) return false;
if(ReferenceEquals(this, obj)) return true;
if(obj.GetType() != GetType()) return false;
return Equals((Dto)obj);
}
public override int GetHashCode()
{
unchecked
{
return(base.GetHashCode() * 397) ^ Id.GetHashCode();
}
}
}
The HasId
class:
public abstract class HasId : IHasId
{
public abstract long? Id { get; set; }
public abstract Guid ManualId { get; protected set; }
protected bool Equals(HasId other)
{
return Id == other.Id && ManualId.Equals(other.ManualId);
}
public override bool Equals(object obj)
{
if(ReferenceEquals(null, obj)) return false;
if(ReferenceEquals(this, obj)) return true;
if(obj.GetType() != GetType()) return false;
return Equals((HasId) obj);
}
public override int GetHashCode()
{
unchecked
{
return(Id.GetHashCode() * 397) ^ ManualId.GetHashCode();
}
}
}
The class doing the HttpRequest:
public class HttpHelper
{
private readonly HttpClient _client = new();
public async Task<TResult> GetObject<TResult>(string requestUri)
{
var response = await _client.GetAsync(requestUri);
response.EnsureSuccessStatusCode();
var valueInJsonFormat = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<TResult>(valueInJsonFormat);
}
public async Task<TResult> PostObject<T, TResult>(T obj, string requestUri)
{
var json = JsonConvert.SerializeObject(obj);
var data = new StringContent(json, Encoding.UTF8, "application/json");
var response = await _client.PostAsync(new Uri(requestUri), data);
if (response.StatusCode != HttpStatusCode.OK)
{
var httpContent =
JsonConvert.DeserializeObject<HttpResponseContent>(await response.Content.ReadAsStringAsync());
try
{
response.EnsureSuccessStatusCode();
}
catch(Exception e)
{
throw new Exception(httpContent?.Detail ?? e.Message, e);
}
}
var result = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<TResult>(result);
}
}
This is the JSON-String:
[
{"Author":
{
"Id":1,
"Settings":
{
"Id":1,
"ArchiveXml":false,
"CreatePdfImmediately":false,
"OverwriteExistingXml":false,
"SaveSimilarTopic":false,
"PdfNameTemplate":null,"PdfPath":null,
"ManualId":"624fa6e3-0864-40bf-87c3a7fcaa1421d4"
},
"Name":"Admindef",
"IsAdmin":true,
"PublicKey" : PUBLIC-KEY HERE (removed since its not relevant),
"ManualId":"f15cb1a5-2d66-4ca9-8dc6-1bf5c25bc7f8"},"Operation":0}]
CodePudding user response:
As far as I understand, you are trying to POST
a JSON
string with a ManualId
in it, but in the service, you don't get the same ManualId
as in your json
.
I think the problem is that your method to set
the ManualId
is protected
.
See here:
public abstract Guid ManualId { get; protected set; }
Protecting it means it won't be set
from the deserialisation.
You should use the default get and set pair like here:
public abstract Guid ManualId { get; set; }
See if this fixes your issue?
This change can also be related to your Dto
class and your HasId
class.
If you want to be able to set the property from the JSON but keep it protected in the code, then you should create a constructor with the parameters you want to deserialize.
Deserialisation follows the following principle:
And you need to be sure that in this graph you will end up calling a constructor with parseable parameters.