I am trying to parse a simple XML file in a Xamarin (Visual Studio) Forms app. I am using the example provided here
It does not work. The serializer returns a list of Node objects, but they are empty. I am including my code below, but it should be identical to the example with some name changes. My XML file is in the Solution root and its Build Action is configured as an Embedded Resource.
namespace EZCal
{
public partial class MainPage : ContentPage
{
// description of a menu tree node
public class Node
{
// TODO: move strings to external file so they can be Localized
public int id { get; set; } // the ID of this node. Never null
public int idParent { get; set; } // NULL for top-level nodes
public String desc1 { get; set; } // text to be displayed - line 1
public String desc2 { get; set; } // text to be displayed - line 1
public String command { get; set; } // command string to be sent to device
}
public MainPage()
{
InitializeComponent();
this.parseXML();
}
void parseXML() {
var assembly = System.Reflection.IntrospectionExtensions.GetTypeInfo(typeof(MainPage)).Assembly;
System.IO.Stream stream = assembly.GetManifestResourceStream("EZCal.MenuDefinitions.xml");
List<Node> menuNodes;
using (var reader = new System.IO.StreamReader(stream))
{
var serializer = new XmlSerializer(typeof(List<Node>));
menuNodes = (List<Node>) serializer.Deserialize(reader);
}
var listView = new ListView();
listView.ItemsSource = menuNodes;
}
}
}
Here is my XML file:
<?xml version="1.0" encoding="UTF-8" ?>
<ArrayOfNode xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Node>
<NodeId>1</NodeId>
<ParentId>0</ParentId>
<Display1>Home line 1</Display1>
<Display2>Home line 2</Display2>
<Command>Home Command</Command>
</Node>
<Node>
<NodeId>2</NodeId>
<ParentId>1</ParentId>
<Display1>Help line 1</Display1>
<Display2>Help line 2</Display2>
<Command>Help Command</Command>
</Node>
<Node>
<NodeId>3</NodeId>
<ParentId>1</ParentId>
<Display1>Diags line 1</Display1>
<Display2>Diags line 2</Display2>
<Command>Diags Command</Command>
</Node>
<Node>
<NodeId>4</NodeId>
<ParentId>1</ParentId>
<Display1>Access line 1</Display1>
<Display2>Access line 2</Display2>
<Command>Access Command</Command>
</Node>
</Node>
</ArrayOfNode>
The names of the properties in your model need to match the names of the nodes in your XML in order for the deserialization to work automatically.
Alternatively, you can apply a mapping attribute
[XmlElement("NodeId")]
public int id { get; set; }
Related
I am using Refit 6.1.15 in a Xamarin forms project. My code works exactly as expected on Android, but on iOS, I get a "The type initializer for 'System.Text.Json.JsonSerializer' threw an exception." when I execute my api.
I am using Microsoft.Extensions for DI - my configuration of my service in my Startup.cs class looks like this:
services.AddRefitClient<IAuthorizeApi>()
.ConfigureHttpClient(c => c.BaseAddress = new Uri(BaseAddress))
.AddTransientHttpErrorPolicy(builder => builder.WaitAndRetryAsync(new[]
{
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(5),
TimeSpan.FromSeconds(15)
}));
My IAuthorizeAPI looks like this:
using System;
using System.Threading.Tasks;
using CivicMobile.Models;
namespace CivicMobile.Services
{
public interface IAuthorizeApi
{
[Post("/v1/DataStage/UserAuthentication/Authenticate?companyCode={queryParms.companyCode}&username={queryParms.username}&password={queryParms.password}&deviceIdentifier={queryParms.deviceIdentifier}")]
[QueryUriFormat(UriFormat.Unescaped)]
Task<ApiResponse<AuthResponse>> Login(Authorize queryParms);
}
My call that throws the error (in my ViewModel) is:
var authToken = await _authenticateService.Login(queryParms);
The return value for the Login (wrapped in ApiResponse) looks like this:
namespace CivicMobile.Models
{
public class AuthResponse
{
[AliasAs("access_token")]
public string AccessToken { get; set; }
[AliasAs("token_type")]
public string TokenType { get; set; }
[AliasAs("expires_in")]
public int ExpiresIn { get; set; }
[AliasAs("userName")]
public string Username { get; set; }
[AliasAs("userIdentifier")]
public string UserIdentifier { get; set; }
[AliasAs(".issued")]
public string IssuedAt { get; set; }
[AliasAs(".expires")]
public string ExpiresAt { get; set; }
}
I have replaced [AliasAs()] with [JsonPropertyName()] but the results are the same.
This error ONLY occurs on iOS - not on Android. Any suggestions?
Add the following code in your iOS(.csproj ):
<ItemGroup>
<PackageReference Include="System.Memory" Version="4.5.4">
<IncludeAssets>none</IncludeAssets>
</PackageReference>
<PackageReference Include="System.Buffers" Version="4.5.1">
< IncludeAssets>none</IncludeAssets>
</PackageReference>
</ItemGroup>
I took refit out of my DI Container and the problem went away entirely. No other changes in my code at all. I will try another DI system as I prefer to use DI in this app and refit.
Another update - I had AddHttpClient as well as the AddRefitClient in my ConfigureServices method. It was actually dead code (as I migrated to Refit but never got rid of dead code). That caused my POST to return a proper ApiResponse object with Content that was deserialized properly. So back to what I had planned in the beginning - thanks for your suggestion - it was helpful on another issue (a very large dataset returning - different Api).
we have the following serilog code, collections and simple strings are being written as expected, but when we try to log an object, serilog outputs the following rater than the object, is there any other setup that needs to be done to log all the properties of the metadata object ?
[16:40:59 INF] Processing {"$type": "Metadata"}
[16:40:59 INF] Processing Program+Metadata
Note: we are using this from a console application
using System;
using System.Collections.Generic;
using Serilog;
class Program
{
public static void Main(string[] args)
{
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Information()
.WriteTo.Console()
.WriteTo.File("log.txt",
rollingInterval: RollingInterval.Day,
rollOnFileSizeLimit: true)
.CreateLogger();
Metadata metadata =new Metadata();
metadata.Name = "hello";
var fruit = new[] { "Apple", "Pear", "Orange" };
Log.Information("In my bowl I have {Fruit}", fruit);
Log.Information("Processing {#HubTableMetadata}", metadata);
Log.Information("Processing {HubTableMetadata}", metadata);
Log.CloseAndFlush();
Console.Read();
}
public class Metadata
{
public string Name;
public string[] Tags;
public List<string> keys;
}
}
Serilog destructures properties, but your Metadata class only defines fields.
To get the behaviour you want, update your Metadata class to use properties:
public class Metadata
{
public string Name { get; set; }
public string[] Tags { get; set; }
public List<string> Keys { get; set; }
}
If you want to customize the output structured data, you can take a look the different Destructurama projects.
You might also be interested in reading this post "Using attributes to control destructuring in Serilog".
I have the following C# code which is getting a "high" error from Checkmarx. I can't see anything wrong with it.
var dataDirectoryPath = AppDomain.CurrentDomain.GetData("DataDirectory").ToString();
var json = File.ReadAllText($"{dataDirectoryPath}{Path.DirectorySeparatorChar}somefile.json");
var settings = new
JsonSerializerSettings{TypeNameHandling=TypeNameHandling.None};
var targetPathSettings = JsonConvert.DeserializeObject<List<TargetPathSetting>>(json, settings);
It gives this error:
The serialized object ReadAllText processed in xxx in the file yyy is deserialized by DeserializeObject in the file zzz
The C# code is as follows:
public class TargetPathSetting
{
public string PathSettingName { get; set; }
public PathSetting PathSetting { get; set; }
}
public class PathSetting
{
public string BaseUrl { get; set; }
public string ApplicationIdUri { get; set; }
}
I can't see that anything that is ever in the file is going to cause any sort of problem, especially with the TypeNameHandling.None setting.
The problem is with the standard Checkmarx query for c #. In this case, Checkmarx does not recognize the correction of this code. To fix it you should use CxAudit and modify this query.
I have a web method that accepts object
[WebMethod]
public static void GetObject(object data)
{
}
Also, I have 2 classes:
class ConnectionString
{
public string ConnectionString { get; set; }
public DatabaseType DatabaseType { get; set; }
}
class Path
{
public string Path { get; set; }
public bool IsNetwork { get; set; }
}
On client side, using javascript, i defined 2 similar classes as well:
function ConnectionString() {
this.ConnectionString = '';
this.DatabaseType = 0;
};
function Path() {
this.Path = '';
this.IsNetwork = false;
};
Now, according to user decision, he can ether choose to create log in database or file system. When I send data to the method, my object resulted as null. If I create method
for each object, it works. Is there a way to unbox or desirialize from OBJECT type to ?
You need to create two method overloads that each take in one of the possible classes. In the current implementation the engine does not know what classes should be put in the WSDL...
If you are using WCF you could use [KnownType] attribute to specify which classes your method supports.
I'm trying to get my mysql data in ASP.net MVC3.
The mysql Database Name is supply_db and table name is xcart_orders.
ASP.net code is like below,
(Im just following my book, and just switch to my DB info but it does not work :( )
(I will omit using and namespace)
Web.Config File,
<add name="EFMysqlContext" connectionString="server=XXX.XXX.XXX.XX;User Id=root;pwd=xxx;Persist Security Info=True;database=supply_db"
providerName="Mysql.Data.MySqlClient" />
Abstract/IXcartOrdersRepository.cs
public interface IXcartOrdersRepository
{
IQueryable<XcartOrder> xcart_orders { get; }
}
/Concrete/EFXcartOrderRepository.cs
public class EFXcartOrdersRepository : IXcartOrdersRepository
{
private EFMysqlContext context = new EFMysqlContext();
public IQueryable<XcartOrder> xcart_orders
{
get { return context.xcart_orders; } // I thought the 'xcart_orders' should be match with db table name, isn't it?
}
}
/Entities/XcartOrder.cs
public class XcartOrder
{
[Key]
public int orderid { get; set; }
public string login { get; set; }
public string membership { get; set; }
public decimal subtotal { get; set; }
}
and In my controller,
IXcartOrdersRepository XcartOrdersRepository = new EFXcartOrdersRepository();
int orderCnt = XcartOrdersRepository.xcart_orders.Count();
then error occur, the error message say "{"Table 'supply_db.XcartOrders' doesn't exist"}"
I think I could connect to db, but couldn't get the table.
anybody know which part do I need to change?
Thank you!
can you decorate your Xcartorder class with the Table attribute to explicitly specify the desired name?
[Table("xcart_orders")]
public class XcartOrder
{
...
edit: attribute syntax