Reporting unknown arguments using CommandLineParser - c#

Is there any way to make the Command Line Parser library report unknown arguments?
Given the following options class:
public class Options
{
[Option('i', "int-option", DefaultValue = 10, HelpText = "Set the int")]
public int IntOption { get; set; }
[ParserState]
public IParserState LastParserState { get; set; }
[HelpOption]
public string GetUsage()
{
return HelpText.AutoBuild(this,
HelpText.DefaultParsingErrorsHandler(this, current));
}
}
And the following program:
var options = new Options();
var parser = new Parser(settings =>
{
settings.HelpWriter = Console.Error;
settings.IgnoreUnknownArguments = false;
});
if (parser.ParseArgumentsStrict(args, options))
{
Console.WriteLine("Int value set: {0}", options.IntOption);
}
When calling the program with "MyProgram.exe --unknown"
I just get the default usage information, but no mention of what error made the parsing fail. I'd like to get some kind of indication to the user what went wrong.

Long story short: with the current implementation you can't get any info about the unknown options.
The long story:
If you put a brakepoint into your GetUsage method you will see that the LastParserState is not null but contains 0 element.
LastParserState is basically filled from the ArgumentParser.PostParsingState but the
the LongOptionParser (which in your case is involved because of the -- double dash) is not adding anything to the PostParsingState collection inside its parse method:
Source from Github:
var parts = argumentEnumerator.Current.Substring(2).Split(new[] { '=' }, 2);
var option = map[parts[0]];
if (option == null)
{
return _ignoreUnkwnownArguments ? PresentParserState.MoveOnNextElement :
PresentParserState.Failure;
}
So internally the parser doesn't store any info about what went wrong just record that fact.

Related

System.Text.Json JsonSerializer: Serialization and deserialization of 'System.Type' instances are not supported

I got an error related with security when I tried to deserialize by using `System.Text.Json JsonSerializer`.
What do I want to achieve?
I want to give the user controle to transalte some records in my database, so use can follow this scenario:
1- User can choose model of my class library.
2- After selecting a class, user will select a property(filed) from this class.
3- User will get list of values of the selected property up.
4- Last step is not here right now, user can edit a certian value.
This my piece of code:
MyPage.razor.cs:
[Inject]
private IGenericHttpClient<Type> HttpClient { get; set; }
private Type SelectedType { get; set; }
// First select a class [Class library] from HTML Select
private void OnTypeChnage(ChangeEventArgs args)
{
string FullName = "My.Models." + args.Value.ToString();
// Create type of selected class
SelectedType = Assemble.GetType(FullName, false);
}
//Call api to get all fields of this class
private async Task OnPropertChange(ChangeEventArgs args)
{
var list = await
HttpClient.GetJsonAsync($"/api/{SelectedType.Name}/all");
}
GenericHttpClient.cs
public async ValueTask<List<T>> GetJsonAsync(string url)
{
using HttpResponseMessage response = await _client.GetAsync(url);
ValidateResponse(response);
var conetnt = await response.Content.ReadAsStringAsync();
//I got the error down
return JsonSerializer.Deserialize<List<T>>(conetnt, new JsonSerializerOptions() { PropertyNameCaseInsensitive=true});
}
System.Text.Json does not support Type class due to security reasons. You send the full assembly name as a string and again try to construct the Type at the client end.
public async ValueTask<List<T>> GetJsonAsync(string url) this wont even compile, due to not specify generic information on method signature.
And also, your problem would come from the content of http response, otherwise, the Deserialize step should work fine.
I copied your code and make a small block that prove it.
// Define somewhere
public class GenericHttpClient
{
public List<T> GetJsonAsync<T>()
{
var content = "[{\"TestProp\": \"This is some test\"}]";
return JsonSerializer.Deserialize<List<T>>(content, new JsonSerializerOptions() { PropertyNameCaseInsensitive=true});
}
}
public class Test
{
public string TestProp { get; set; }
}
// Test it
var test = new GenericHttpClient();
var result = test.GetJsonAsync<Test>();
Like what #Mayur Ekbote mentioned up, "System.Text.Json does not support Type class due to security reasons." I will add a solution but I don't think this solution is very efficient.
Change Type to Dynamic:
[Inject]
private IGenericHttpClient<dynamic> HttpClient { get; set; }
Use JsonElement to get the value as a string:
private async Task OnPropertChange(ChangeEventArgs args)
{
var langCode = CultureInfo.CurrentCulture.Name;
PropertyValueList.Clear();
var list = await HttpClient.GetJsonAsync($"/api/{SelectedType.Name}/all");
List<object> listValue = new List<object>();
SelectedProperty = args.Value.ToString();
string fieldName = char.ToLower(SelectedProperty[0]) + SelectedProperty.Substring(1);
foreach (var item in list)
{
//Convert object to JsonElement
var val = ((JsonElement)item).GetProperty(fieldName).GetString();
PropertyValueList.Add(val);
}
}
Why is it not efficient?
Because I got a list of value String instead of list of selected class.

how to Serialize .Net Class to Avro.Generic.GenericRecord for publishing into kafka topic?

I am trying to find a way/helper to convert.Net Class to Avro.Generic.GenericRecord . Currently, I am manually adding field-name and field-value to Generic record. Is there a serializer/converter which I can use to convert the object to generic record and publish on to a kafka topic.
class Plant
{
public long Id { get; set; }
public string Name { get; set; }
public List<PlantProperties> PlantProperties{ get; set; }
}
class PlantProperties
{
public long Leaves{ get; set; }
public string Color{ get; set; }
}
Please suggest.
Assuming you are using the Confluent Schema Regsitry, you can use their .NET client1
https://github.com/confluentinc/confluent-kafka-dotnet
Copied from the examples folder
using (var serdeProvider = new AvroSerdeProvider(avroConfig))
using (var producer = new Producer<string, GenericRecord>(producerConfig, serdeProvider.GetSerializerGenerator<string>(), serdeProvider.GetSerializerGenerator<GenericRecord>()))
{
Console.WriteLine($"{producer.Name} producing on {topicName}. Enter user names, q to exit.");
int i = 0;
string text;
while ((text = Console.ReadLine()) != "q")
{
var record = new GenericRecord(s);
record.Add("name", text);
record.Add("favorite_number", i++);
record.Add("favorite_color", "blue");
producer
.ProduceAsync(topicName, new Message<string, GenericRecord> { Key = text, Value = record })
.ContinueWith(task => task.IsFaulted
? $"error producing message: {task.Exception.Message}"
: $"produced to: {task.Result.TopicPartitionOffset}");
}
}
cts.Cancel();
}
Where, in your case, update the record.Add uses accordingly
However, since you have a class, therefore, you should try to use SpecificRecord, rather than serializing back and forth between Avro and a .NET class via a GenericRecord. See the README section on the AvroGen tool for examples of this
1. I'm not aware of an alternative .NET library
Below are the steps I did to solve the problem using the suggestion from #cricket_007.
To avoid the complexity of writing the avro schema, create the c# classes first then use AvroSerializer to generate schema.
AvroSerializer.Create().WriterSchema.ToString()
This will generate the schema json for the class.
Move it to a schema file and
Make all the types to have nulls as Required
Then used avro_gen.exe tool to regenerate class files which implements ISpecific Record.
Add used the below code to publish to queue
using (var serdeProvider = new AvroSerdeProvider(avroConfig))
using (var producer = new Producer<string, MYClass>(producerConfig,
serdeProvider.GetSerializerGenerator<string>(),
serdeProvider.GetSerializerGenerator<MYClass>()))
{
Console.WriteLine($"{producer.Name} producing on
{_appSettings.PullListKafka.Topic}.");
producer.ProduceAsync(_appSettings.PullListKafka.Topic, new
Message<string, MYClass> { Key = Guid.NewGuid().ToString(), Value = MYClassObject})
.ContinueWith(task => task.IsFaulted
? $"error producing message: {task.Exception.Message}"
: $"produced to: {task.Result.TopicPartitionOffset}");
}
some links to help do this.
https://shanidgafur.github.io/blog/apache-avro-on-dotnet
https://github.com/SidShetye/HelloAvro/tree/master/Avro

Elegant way to copy properties from object to another

I've got a small integration service which recieves XML files and parses it.
Also I've created classes from provided XSD for deserializing XML data. During parsing I need to copy properties from those XSD-generated classes to my own that I use in Data Layer. This is an example of my aproach
var supplierInfo = new SupplierInfo();
//coping properties
supplierInfo.Name = supplier.name;
supplierInfo.ShortName = supplier.shortName;
supplierInfo.BrandName = supplier.brandName;
supplierInfo.AdditionalFullName = supplier.additionalFullName;
supplierInfo.AdditionalCode = supplier.additionalCode;
supplierInfo.AdditionalInfo = supplier.additionalInfo;
//lot's of other properties
//...
supplierInfo.Tax = supplier.tax;
supplierInfo.RegistrationDate = supplier.registrationDate;
Some times ammount of properties is very big. Is there more eligant way to copy those properties?
Automapper has been out there since ages ago. Tried and tested. http://automapper.org/
Here's an example:
using System;
using AutoMapper;
public class Program
{
class SupplierInfo
{
public SupplierInfo( string name, string shortName, string brandName ) {
Name = name;
ShortName = shortName;
BrandName = brandName;
}
public string Name {get; private set; }
public string ShortName {get; private set; }
public string BrandName {get; private set; }
}
class Supplier
{
public string name {get; set; }
public string shortName {get; set; }
public string brandName {get; set; }
}
public static void Main()
{
var dto = new Supplier() {
name = "Name 1",
shortName = "Short Name 1",
brandName = "Brand Name 1"
};
//From the tutorial:
//You only need one MapperConfiguration instance typically per AppDomain and should be instantiated during startup.
var config = new MapperConfiguration(cfg => cfg.CreateMap<Supplier, SupplierInfo>());
var mapper = config.CreateMapper();
SupplierInfo info = mapper.Map<SupplierInfo>(dto);
Console.WriteLine( info.Name );
Console.WriteLine( info.ShortName );
Console.WriteLine( info.BrandName );
}
}
The official Getting Started guide can be found at https://github.com/AutoMapper/AutoMapper/wiki/Getting-started
I am happy to be corrected on this but I always find automapper (as per the other answer), which maps property values by name/convention, a little scary to use in production code.
I don't really have a decent alternative but I prefer to do it manually as per your code sample - it's easier to read and debug and if you end up renaming any properties in a class, it will be clear that the copying code is broken (or if you use some IDE tool to rename the property, it'll change the copy code accordingly).
First, install EntityLite.Core:
PM> Install-Package EntityLite.Core
Then use it:
using inercya.EntityLite.Extensions;
...
supplierInfo.AssignPropertiesFrom(supplier);
EntityLite is a micro ORM I developed. It has some little gems :-)
EDIT:
I guess you may not want to install EntityLite.Core just to copy some properties from an object to another. So here you have an implementation of AssignPropertiesFrom extension method that uses Reflection:
public static class ObjectExtensions
{
public static void AssignPropertiesForm(this object target, object source)
{
if (target == null || source == null) throw new ArgumentNullException();
var targetPropertiesDic = target.GetType().GetProperties().Where(p => p.CanWrite).ToDictionary(p => p.Name, StringComparer.CurrentCultureIgnoreCase);
foreach (var sourceProp in source.GetType().GetProperties().Where(p => p.CanRead))
{
PropertyInfo targetProp;
if (targetPropertiesDic.TryGetValue(sourceProp.Name, out targetProp))
{
targetProp.SetValue(target, sourceProp.GetValue(source, null), null);
}
}
}
}
Incidentally, this is not the EntityLite implementation. EntityLite uses dynamic IL generation.

Find a generic DbSet in a DbContext dynamically

I know this question has already been asked but I couldn't find an answer that satisfied me. What I am trying to do is to retrieve a particular DbSet<T> based on its type's name.
I have the following :
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("MyDllAssemblyName")]
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("MyCallingAssemblyName")]
class MyDbContext : DbContext {
public DbSet<ModelA> A { get; set; }
public DbSet<ModelB> B { get; set; }
public dynamic GetByName_SwitchTest(string name) {
switch (name) {
case "A": return A;
case "B": return B;
}
}
public dynamic GetByName_ReflectionTest(string fullname)
{
Type targetType = Type.GetType(fullname);
var model = GetType()
.GetRuntimeProperties()
.Where(o =>
o.PropertyType.IsGenericType &&
o.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>) &&
o.PropertyType.GenericTypeArguments.Contains(targetType))
.FirstOrDefault();
if (null != model)
return model.GetValue(this);
return null;
}
}
I have no trouble getting the type itself whether it is via a simple switch or reflection. I need however to return the type as a dynamic since I do not know what DbSet type it will be.
Then somewhere else in the same assembly, I use it this way :
// MyDbContext MyDbContextInstance..
var model = MyDbContextInstance.GetByName_SwitchTest("A");
var record1 = model.FirstOrDefault(); // It crashes here with RunTimeBinderException
At this point model contains an instance of a InternalDbSet<ModelA> type. From there, any use I do with the model object I get a RunTimeBinderException :
'Microsoft.Data.Entity.Internal.InternalDbSet' does not contain a definition for 'FirstOrDefault'
Investigating on the web, I found a blog post explaining that (dixit his blog) :
the reason the call to FirstOrDefault() fails is that the type
information of model is not available at runtime. The reason it's not
available is because anonymous types are not public. When the method
is returning an instance of that anonymous type, it's returning a
System.Object which references an instance of an anonymous type - a
type whose info isn't available to the main program.
And then he points that a solution :
The solution is actually quite simple. All we have to do is open up
AssemplyInfo.cs of the ClassLibrary1 project and add the following
line to it: [assembly:InternalsVisibleTo("assembly-name")]
I did try this solution on my code but it doesn't work. For info I have an asp.net 5 solution with two assemblies running on dnx dotnet46. An app and a dll containing all my models and DbContext. All the concerned calls I do are located on the dll though.
Does this solution have any chance to work ?
Am I missing something ?
Any pointers would be greatly appreciated ?
Thanks in advance
[EDIT]
I have tried to return IQueryable<dynamic> rather than dynamic and I could do the basic query model.FirstOrDefault(); but above all I'd like to be able to filter on a field too :
var record = model.FirstOrDefault(item => item.MyProperty == true);
So how did I do it when I am not aware of <T> during compile time.
First need to get the type as DbContext.Set method returns a non-generic DbSet instance for access to entities of the given type in the context and the underlying store.
public virtual DbSet Set(Type entityType)
Note here argument is the type of entity for which a set should be returned.And set for the given entity type is the return value.
var type = Assembly.GetExecutingAssembly().GetTypes().FirstOrDefault(t => t.Name == <Pass your table name>);
now once I have this type
if(type != null)
{
DbSet context = context.Set(type);
}
Or a one liner would be
DbSet mySet = context.Set(Type.GetType("<Your Entity Name>"));
*Disclaimer: This response doesn't give a stricto sensu answer to my question. It is rather a different approach to resolve my own problem. I am aware this is a specific example for a given situation that will not work for everyone. I am posting this approach in the hope it helps someone but will not mark it as the answer as I am still hoping for a real solution.
To start with, let's accept the fact that the only useful information we can get out of the current code is whether a record exists or not.. Any attempt of a dynamic queries after that would give the RuntimeBinderException.
Then let's continue with another fact; DbContext.Add(object) and DbContext.Update(object) are not template based so we can use them to save our models ( Instead of db.A.Add() or db.A.Update() )
In my own situation, no more is required to work out a procedure
Define models a little differently
To start with, I need a field that is retrievable across all my models which should obviously be a way to identify a unique record.
// IModel give me a reliable common field to all my models ( Fits my DB design maybe not yours though )
interface IModel { Guid Id { get; set; } }
// ModelA inherit IModel so that I always have access to an 'Id'
class ModelA : IModel {
public Guid Id { get; set; }
public int OtherField { get; set; }
}
// ModelB inherit IModel so that I always have access to an 'Id'
class ModelB : IModel {
public Guid Id { get; set; }
public string WhateverOtherField { get; set; }
}
Re-purpose the dynamic queries a bit to do something we know works
I haven't found a way to do smart query dynamically, so instead I know I can reliably identify a record and know if it exists or not.
class MyDbContext : DbContext {
public DbSet<ModelA> A { get; set; }
public DbSet<ModelB> B { get; set; }
// In my case, this method help me to know the next action I need to do
// The switch/case option is not pretty but might have better performance
// than Reflection. Anyhow, this is one's choice.
public bool HasRecord_SwitchTest(string name) {
switch (name) {
case "A": return A.AsNoTracking().Any(o => o.Id == id);
case "B": return B.AsNoTracking().Any(o => o.Id == id);
}
return false;
}
// In my case, this method help me to know the next action I need to do
public bool HasRecord_ReflectionTest(string fullname)
{
Type targetType = Type.GetType(fullname);
var model = GetType()
.GetRuntimeProperties()
.Where(o =>
o.PropertyType.IsGenericType &&
o.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>) &&
o.PropertyType.GenericTypeArguments.Contains(targetType))
.FirstOrDefault();
if (null != model)
return (bool)model.GetValue(this).AsNoTracking().Any(o => o.Id == id);
return false;
}
// Update and save immediately - simplified for example
public async Task<bool> UpdateDynamic(object content)
{
EntityEntry entry = Update(content, GraphBehavior.SingleObject);
return 1 == await SaveChangesAsync(true);
}
// Insert and save immediately - simplified for example
public async Task<bool> InsertDynamic(object content)
{
EntityEntry entry = Add(content, GraphBehavior.SingleObject);
return 1 == await SaveChangesAsync(true);
}
}
A little bit of plumbing to give a sense to my situation
Next, what I needed to do with that dynamic queries was a way to replicate data from a server down to my client. ( I have omitted a big chunk of the architecture to simplify this example )
class ReplicationItem
{
public ReplicationAction Action { get; set; } // = Create, Update, Delete
public string ModelName { get; set; } // Model name
public Guid Id { get; set; } // Unique identified across whole platform
}
Connecting the bits.
Now, here's the routine that connects the bits
public async void ProcessReplicationItem(ReplicationItem replicationItem)
{
using (var db = new MyDbContext())
{
// Custom method that attempts to get remote value by Model Name and Id
// This is where I get the strongly typed object
var remoteRecord = await TryGetAsync(replicationItem.ModelName, replicationItem.Id);
bool hasRemoteRecord = remoteRecord.Content != null;
// Get to know if a local copy of this record exists.
bool hasLocalRecord = db.HasRecord_ReflectionTest(replicationItem.ModelName, replicationItem.Id);
// Ensure response is valid whether it is a successful get or error is meaningful ( ie. NotFound )
if (remoteRecord.Success || remoteRecord.ResponseCode == System.Net.HttpStatusCode.NotFound)
{
switch (replicationItem.Action)
{
case ReplicationAction.Create:
{
if (hasRemoteRecord)
{
if (hasLocalRecord)
await db.UpdateDynamic(remoteRecord.Content);
else
await db.InsertDynamic(remoteRecord.Content);
}
// else - Do nothing
break;
}
case ReplicationAction.Update:
[etc...]
}
}
}
}
// Get record from server and with 'response.Content.ReadAsAsync' type it
// already to the appropriately
public static async Task<Response> TryGetAsync(ReplicationItem item)
{
if (string.IsNullOrWhiteSpace(item.ModelName))
{
throw new ArgumentException("Missing a model name", nameof(item));
}
if (item.Id == Guid.Empty)
{
throw new ArgumentException("Missing a primary key", nameof(item));
}
// This black box, just extrapolate a uri based on model name and id
// typically "api/ModelA/{the-guid}"
string uri = GetPathFromMessage(item);
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:12345");
HttpResponseMessage response = await client.GetAsync(uri);
if (response.IsSuccessStatusCode)
{
return new Response()
{
Content = await response.Content.ReadAsAsync(Type.GetType(item.ModelName)),
Success = true,
ResponseCode = response.StatusCode
};
}
else
{
return new Response()
{
Success = false,
ResponseCode = response.StatusCode
};
}
}
}
public class Response
{
public object Content { get; set; }
public bool Success { get; set; }
public HttpStatusCode ResponseCode { get; set; }
}
ps: I am still interested in a real answer, so please keep posting for other answer if you have a real one to share.
You could use this to get the DBSet for a specific type:
public object GetByType(DbContextcontext, Type type) {
var methode = _context.GetType().GetMethod("Set", types: Type.EmptyTypes);
if (methode == null) {
return null;
}
return methode.MakeGenericMethod(type).Invoke(_context, null);
}

C# Razor - Display value from list based on key

I'm trying to display some text from a list depending on the key:
<td>#x.OutcomeSummary</td>
<td>#Model.SummaryOutcomes.FirstOrDefault(c => c.Value == x.OutcomeSummary).Name</td>
<td>#Model.SummaryOutcomes.FirstOrDefault(x.OutcomeSummary).Name</td>
In this case x.OutcomeSummary is 7 and I would like for it to get the relevant text from SummaryOutcomes with a key of 7.
The second line gives me the following error: System.NullReferenceException: Object reference not set to an instance of an object.
And the third line gives me an error saying that the FirstOrDefault command has invalid arguments.
It imports the following model:
public class DogSummaryView
{
public IEnumerable<DogIncident> Incidents { get; set; }
public IEnumerable<Category> SummaryOutcomes { get; set; }
public IEnumerable<Category> DogBreeds { get; set; }
}
This is the category class:
public class Category
{
public string Value { get; set; }
public string Name { get; set; }
public bool InUse { get; set; }
}
And this is the controller:
public ActionResult Summary()
{
var vm = new DogSummaryView
{
Incidents = repository.GetAllRecords().OrderByDescending(x => x.DateRecieved),
SummaryOutcomes = repository.GetAllSummaryOutcomes()
};
return View("Summary", vm);
}
And finally here you can see that the list is populated and initialized:
Is there anyway of getting it so that instead of displaying 7, it displays the correct summary outcome?
Thanks
Thank you so so much to fourpastmidnight for his persistent help with this, and not only helping me to find a solution, but also helping me to understand just exactly where the problem lied. Here's an updated (working!) solution:
#foreach (var x in Model.Incidents)
{
var summaryOutput = "";
var firstOutcomeSummary = Model.SummaryOutcomes.FirstOrDefault(c => c.Value == x.OutcomeSummary);
if (firstOutcomeSummary != null) { summaryOutput = Model.SummaryOutcomes.FirstOrDefault(c => c.Value == x.OutcomeSummary).Name.ToString(); }
<tr>
<td>#Html.Raw(summaryOutput)</td>
</tr>
}
Ok, the problem is you're trying to compare a string to an int.
Change the second line as follows:
#Model.SummaryOutcomes.FirstOrDefault(c => c.Value == x.OutcomeSummary.ToString()).Name;
// You could also use '.Value'.
That should solve your problem.
UPDATE
Hmm, maybe x.OutcomeSummary.ToString() is resulting in the type name of the enumeration and not the integer value of the enumeration constant value.
Try updating the above line to the following:
#Model.SummaryOutcomes.FirstOrDefault(c => c.Value == ((int)x.OutcomeSummary).ToString()).Name;
UPDATE 2014-03-21
According to the OP's latest comment, try the following:
// If x.OutcomeSummary is the outcome summary name, then....
var firstOutcomeSummary = #Model.SummaryOutcomes.FirstOrDefault(c => c.Name == x.OutcomeSummary)
if (firstOutcomeSummary != null)
// Do something here.
// Else, if x.OutcomeSummary is the outcome summary value, e.g. "7", then...
var firstOutcomeSummary = #Model.SummaryOutcomes.FirstOrDefault(c => c.Value == x.OutcomeSummary)
if (firstOutcomeSummary != null)
// Do something here.
FirstOrDefault will do just that return the first element that matches the predicate or return default, i.e. null. Calling .Name on a null object will throw a NullReferenceException
In sum, the behavior you are describing will occur if there's no instance of Category in the enumeration SummaryOutcomes whose value is 7.

Categories