I have a relatively simple console app (framework) which has a tightly coupled classes with properties and my main triggers an async task. These are my property classes:
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Net.Http; //for HTTP client
using System.Reflection;
using System.Threading.Tasks; //for Async Request/Response
using Newtonsoft.Json; //for JSON properties
namespace PSD2
{
[Serializable]
public class PS
{
public System.Uri BaseURL { get; set; } = new System.Uri("http://192.999.999.999:8888/some/url/here/");
public ConsHeaders Headers { get; set; }
public ConsBody Body { get; set; }
public consAttributes Attributes { get; set; }
}
[Serializable]
public partial class ConsHeaders
{
[JsonProperty("Core-ID")]
public string corID { get; set; }
[JsonProperty("PS-Token")]
public string PS_Token { get; set; }
[JsonProperty("Req-ID")]
public string reqID { get; set; }
}
[Serializable]
public partial class consAttributes
{
[JsonProperty("consId")]
public string consId { get; set; } = String.Empty;
[JsonProperty("consStatus")]
public string consStatus { get; set; } = String.Empty;
[JsonProperty("userName")]
public string userName { get; set; } = String.Empty;
};
[Serializable]
public partial class consBody
{
[JsonProperty("access")]
public AccessHeaders access { get; internal set; }
[JsonProperty("combinedServiceIndicator")]
public Boolean CombinedServiceIndicator { get; set; } = false;
[JsonProperty("frequencyPerDay")]
public int FrequencyPerDay { get; set; } = 4;
[JsonProperty("recurringIndicator")]
public Boolean RecurringIndicator { get; set; } = false;
[JsonProperty("validUntil")]
public string ValidUntil { get; set; } = "9999-12-31";
}
...
Now, my Program class creates an object and in Main I call a class called testing who has my logic behind, nothing more than populating the object properties with values, and calls a Task asycn which is also present inside. Code continues from above as:
public class Program
{
public static PS cnsnt = new PS();
public static void Main(string[] args)
{
Testing test = new Testing();
test.createCONS();
}
public class Testing
{
public void createCONS()
{
try
{
cnsnt.Headers = new ConsHeaders
{
corID = "Something",
reqID = "AnotherThing",
PS_Token = "myTokenValue"
};
cnsnt.Body = new ConsBody
{
access = new AccessHeaders
{
AllPsd2 = "allAccounts",
AvailableAccounts = "YES"
},
CombinedServiceIndicator = false,
FrequencyPerDay = 10,
ValidUntil = "2020-12-31"
};
cnsnt.Attributes = new consAttributes
{
consId = "",
_links_self_href = "",
consStatus = "",
status_href = "",
userName = ""
};
}
catch (System.Exception e)
{
throw new System.Exception("Error - Aborting..");
}
myConsAsync(cnsnt.BaseURL, cnsnt, HttpMethod.Post).GetAwaiter().GetResult();
}
public async static Task myConsAsync(Uri HTTPaddress, PS ConSent, HttpMethod httpMethod)
{
try
{
HttpClient client = new HttpClient();
System.Text.UTF8Encoding utf8 = new System.Text.UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true);
using (HttpRequestMessage request = new HttpRequestMessage(httpMethod, HTTPaddress))
{
client.BaseAddress = HTTPaddress;
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("Connection", "keep-alive");
client.DefaultRequestHeaders.Add("Cache-Control", "no-cache");
//...
client.DefaultRequestHeaders.Add("Core-ID", ConSent.Headers.corID);
client.DefaultRequestHeaders.Add("Req-ID", ConSent.Headers.reqID);
client.DefaultRequestHeaders.Add("PS-Token", ConSent.Headers.PS_Token);
//...
request.Content = new StringContent(JsonConvert.SerializeObject(ConSent, Formatting.Indented), utf8, "application/json");
using (HttpResponseMessage response = await client.SendAsync(request).ConfigureAwait(false))
{
response.EnsureSuccessStatusCode();
Int32 code = (Int32)response.StatusCode;
string responseBody = response.Content.ReadAsStringAsync().Result.ToString();
try
{
if (responseBody.Contains("consId"))
{
try
{
string responseValues = JSONtoKeyValue(responseBody);
var dict = responseValues.Split('|')
.Select(x => x.Split('='))
.Where(x => x.Length > 1
&& !String.IsNullOrEmpty(x[0].Trim())
&& !String.IsNullOrEmpty(x[1].Trim()))
.ToDictionary(x => x[0].Trim(), x => x[1].Trim());
foreach (KeyValuePair<string, string> entry in dict)
{
if (entry.Value == null)
{
dict.Remove(entry.Key);
}
else
{
string key = entry.Key;
string value = entry.Value;
try
{
if (cnsnt.Attributes.GetType().GetTypeInfo().GetDeclaredProperty(key) != null)
{
// ---> ERROR: Object reference not set to an instance of an object.
cnsnt.GetType().GetTypeInfo().GetDeclaredProperty(key).SetValue(cnsnt, entry.Value);
}
}
catch (System.Exception e)
{
Console.WriteLine("Failed during processing Property: " + e.Message);
}
}
}
Console.ReadLine();
}
catch (System.Exception e)
{
Console.WriteLine(e.StackTrace + "\r\n" + e.Message);
}
}
else
{
throw new System.Exception("Fatal error reading response body for the consent Id. Aborting..");
};
}
catch (System.Exception e)
{
Environment.Exit(13);
}
}
}
}
catch (Exception e)
{
//whatever, Console.WriteLine("Error in " + e.TargetSite + "\r\n" + e.Message + "\r\n" + e.Data);
}
//return
}
// this works as intended.. included just for completion
public static string JSONtoKeyValue(string pString)
{
pString.Trim();
if (pString == null)
{
return "";
}
else
{
pString = pString.Replace("\r\n", "|").Replace(":", "=").Replace("\"", "").Replace("{", "").Replace("}", "").Replace(",", "");
int j = 0, inputlen = pString.Length;
char[] newarr = new char[inputlen];
for (int i = 0; i < inputlen; ++i)
{
char tmp = pString[i];
if (!char.IsWhiteSpace(tmp))
{
newarr[j] = tmp; ++j;
}
}
return new String(newarr, 0, j).Replace("||", "|").Replace("||", "|").Replace("=|", "_").Trim('|');
}
}
}
}
}
Notice in the Task that I want to read a string separated with pipes (a small method does the work nicely) and I try to see if I have this property in my object, and if yes, to populate the value.
However, in line ConSent.GetType().GetTypeInfo().GetDeclaredProperty(key).SetValue(cnsnt, entry.Value); I get the error "Object reference not set to an instance of an object."
I struggle on this one, could someone help me?
You have made a simple mistake.
You check for
But then you assign with
Just replace it with,
Note its cnsnt. Not ConSent.
and you'll be fine. Happy reflecting!
edit:
saw your edit, same thing.
cnsnt.Attributes.GetType().GetTypeInfo().GetDeclaredProperty(key) cnsnt.GetType().GetTypeInfo().GetDeclaredProperty(key)
you are basically checking on a different bject if it has a property and then you try to set it on another.
Suggestion.
Why not go:
this way it will not fail, ever.