Pass generic list in console app from asp.net - asp.net

I have a solution that i need to call a console app from asp.net and need to pass variables. one variable is a generic list of a certain class.
I have tried passing it but I got error that i cannot convert a generic list to a string which is correct.
I am not sure if there is another way to pass this.
I know webservice can solve this issue. But it there any other options?
Is this possible to do or only string are possible to pass
Here is the generic list sample.
List<person> personList = new List<person>();
person p = new person();
p.name = "test";
p.age = 12;
p.birthdate = 01/01/2014
personList.add(p)
Thanks.

Ok, Console application accepts only strings. This is defined in the Main method as
static void Main(string[] args)
Since you have a complex object list it'll be bit hard to pass this information to the console application (but not impossible). There are several options for you.
Pass your values as comma separated values as a string as long as this string is not too long.
Web Services or a Web API as you suggested.
Serialize your object to an XML file and then deserialize in your console application.
Write and read from a persistent data store
UPDATE
Sample Code for Option 3 (Write to an XML file)
I wrote this sample code out of curiosity. Hope this helps to solve your issue.
ASP.Net Website
I have a button in my web page (Default.aspx) and in it's click event it writes the Person collection/ List to an XML file. Here's the code behind.
using System;
using System.IO;
using System.Xml.Serialization;
namespace WriteToConsole
{
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void btnWriteToConsole_Click(object sender, EventArgs e)
{
PersonCollection personList = new PersonCollection();
// Person 1
Person p = new Person();
p.Name = "test 1";
p.Age = 12;
p.BirthDate = DateTime.Parse("01/01/2014");
personList.Add(p);
// Person 2
Person p2 = new Person();
p2.Name = "test 2";
p2.Age = 25;
p2.BirthDate = DateTime.Parse("01/01/2014");
personList.Add(p2);
XmlSerializer serializer = new XmlSerializer(personList.GetType());
StreamWriter file = new StreamWriter(#"D:\temp\PersonCollection.xml");
serializer.Serialize(file, personList);
file.Close();
}
}
}
And, the Person.cs looks like this.
using System;
using System.Collections.Generic;
namespace WriteToConsole
{
[Serializable]
[System.Xml.Serialization.XmlRoot("PersonCollection")]
public class PersonCollection : List<Person> {
}
[Serializable]
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public DateTime BirthDate { get; set; }
public Person()
{
this.Name = string.Empty;
this.Age = 0;
this.BirthDate = DateTime.MinValue;
}
}
}
Console Application
Then read the XML file in your console application and display the data in personList on the console.
using System;
using System.IO;
using System.Xml.Serialization;
namespace ReadInConsole
{
class Program
{
static void Main(string[] args)
{
XmlSerializer deserializer = new XmlSerializer(typeof(PersonCollection));
TextReader textReader = new StreamReader(#"D:\temp\PersonCollection.xml");
PersonCollection personList = new PersonCollection();
personList = (PersonCollection)deserializer.Deserialize(textReader);
textReader.Close();
if (personList != null && personList.Count > 0)
{
foreach (Person p in personList)
{
Console.WriteLine("Person name: {0}, Age: {1} and DOB: {2}", p.Name, p.Age, p.BirthDate.ToShortDateString());
}
Console.ReadLine();
}
}
}
}
In your console application you should have the same Person class as a modal (This is same as the Person class in your Web Application. Only the namespace is different).
using System;
using System.Collections.Generic;
namespace ReadInConsole
{
[Serializable]
[System.Xml.Serialization.XmlRoot("PersonCollection")]
public class PersonCollection : List<Person>
{
}
[Serializable]
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public DateTime BirthDate { get; set; }
public Person()
{
this.Name = string.Empty;
this.Age = 0;
this.BirthDate = DateTime.MinValue;
}
}
}
Hope you understand the code.

Related

Xamarin App does nothing after await the GetAsync method

I have created a class, in Xamarin Forms, that requests to a web API about the details of countries. Right now, I am testing only with a country.
However, once the line "HttpResponseMessage response = await client.GetAsync(uri);" is executed, the app does nothing additional.
In order to validate if the app executes other instructions after this line, I have included additional lines to write the sequence into the device log.
All the lines before the previous instruction are written into the log and none of them after this instruction.
On the other hand, the screen of the device remains blank, without insert the Label created by code.
Here is the code of the class and the method that consumes the API.
...
using Android.Util;
using System.Net.Http;
using System.Threading.Tasks;
class Country
{
public int iIdCountry { get; set; }
public string sCountryName { get; set; }
public string sCountryIsoCode { get; set; }
public string sCountryPhoneCode { get; set; }
public bool bCountryContainsPrefix { get; set; }
public bool bCountryActive { get; set; }
private static readonly HttpClient client = new HttpClient();
public static async Task<Country> GetCountryAsync(int id)
{
string baseUri = new BaseUri().baseUri;
string sufixUri = "/CountriesApi/GetItem/" + id;
var uri = baseUri + sufixUri;
string tag = "myapp";
Country country = null;
HttpResponseMessage response = await client.GetAsync(uri);
Log.Info(tag, "Response received");
if (response.IsSuccessStatusCode)
{
country = await response.Content.ReadAsAsync<Country>();
Log.Info(tag, "Country received");
}
Log.Info(tag, "Country returned");
return country;
}
}
...
This is the component that makes the call to the previous class:
...
using Android.Util;
using System;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace EnubexMobile.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class Start : ContentPage
{
public Start()
{
var stackLayout = new StackLayout();
string tag = "myapp";
InitializeComponent();
Log.Info(tag, "Started");
var country = Country.GetCountryAsync(1).GetAwaiter().GetResult();
Log.Info(tag, country.sCountryName);
var label = new Label() { Text = country.sCountryName };
Log.Info(tag, "Label created");
stackLayout.Children.Add(label);
Log.Info(tag, "Label added");
}
private void InitializeComponent()
{
throw new NotImplementedException();
}
}
}
...
The idea is to insert a label into the StackLayout with the name of the country received from the API.
Could someone help me to understand what I am missing here?
Thanks !
Regards,

Is there a way to dynamically add a DbSet to EF core and to use Linq against the dynamic DbSet?

I'm using EF Core v. 5.0 and SQLite DB and I'm trying to dynamically add a DbSet to my DbContext. I have followed and readapted this guide to EF Core: https://romiller.com/2012/03/26/dynamically-building-a-model-with-code-first/ and I realized this DbContext class:
internal class GenericAppContext : DbContext
{
public GenericAppContext()
{
//Disable the EF cache system to execute every running the OnModelCreating method.
//ATTENTION: This is a performance loss action!
this.ChangeTracker.LazyLoadingEnabled = false;
}
protected override void OnConfiguring(DbContextOptionsBuilder options)
{
var baseDir = AppDomain.CurrentDomain.BaseDirectory;
//if "bin" is present, remove all the exceeding path starting from "bin" word
if (baseDir.Contains("bin"))
{
int index = baseDir.IndexOf("bin");
baseDir = baseDir.Substring(0, index);
}
options.UseSqlite($"Data Source={baseDir}Database\\TestSQLite.db");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
MethodInfo addMethod = typeof(ModelBuilder).GetMethods().First(e => e.Name == "Entity");
foreach (var assembly in AppDomain.CurrentDomain
.GetAssemblies()
.Where(a => a.GetName().Name != "EntityFramework"))
{
IEnumerable<Type> configTypes = assembly
.GetTypes()
.Where(t => t.BaseType != null
&& t.BaseType.IsGenericType
&& t.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>));
foreach (var type in configTypes)
{
Type entityType = type.BaseType.GetGenericArguments().Single();
object entityConfig = assembly.CreateInstance(type.FullName);
addMethod?.MakeGenericMethod(entityType)
.Invoke(modelBuilder, new object[] { });
}
}
}
}
My "Blog" and "Article" classes:
internal class Blog : EntityTypeConfiguration<Blog>
{
public int Id { get; set; }
public string Name { get; set; }
public string Category { get; set; }
}
internal class Article : EntityTypeConfiguration<Article>
{
[Key]
public int Id { get; set; }
public string Body { get; set; }
}
And here is how I initialized the DbContext, in "tables" variable I can see the "Article" table added dynamically using context.Model.GetRelationalModel().Tables.ToList()
public static string TestMethod()
{
using (var context = new GenericAppContext())
{
string result = string.Empty;
//Ensures that the database for the context exists. If it exists, no action is taken. If it does not exist then the database and all its schema are created.
context.Database.EnsureCreated();
List<ITable> tables = context.Model.GetRelationalModel().Tables.ToList();
}
}
At this point, I succesfully saw the "Article" class added dynamically, but I can't query "Article" using Linq, of course, because it doesn't exist fisically in the DbContext.
Is there a way to use Linq against a dynamic DbSet added table like "Article"?
In the end I solved using "Linq.Dynamic.Core" that allows you to use Linq and writing a lambda expression as a string, and much more, here more info about Dynamic Linq.
Here how I modified the TestMethod() showed before, and how I did the query against the "Article" table added dynamically via my "GenericContextApp" class.
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
public static string TestMethod()
{
using (var context = new GenericAppContext())
{
string result = string.Empty;
//Ensures that the database for the context exists. If it exists, no action is taken. If it does not exist then the database and all its schema are created.
context.Database.EnsureCreated();
IEnumerable<IEntityType> contextEntitiesList = context.Model.GetEntityTypes();
IQueryable<IEntityType> entitiesList = contextEntitiesList.Select(p => p).ToList().AsQueryable();
//Query against the dinamycally added "Article" table. It will return the SQL query as a string.
result = context.Query("Your.Complete.Namespace.Article").Where("Body == \"ciao\"").ToQueryString();
return result;
}
}

How to safe a ObservableCollection within a ObservableCollection in xamarin.forms with Sqlite.net

Last 3 days i tried to save my collection in my database.
I tried it in all sorts of ways... without success.
The last one i tried is to serialize my collection and save it to a byte[] everytime the collection changes.
And on appstart i tried to derserialize it in my collection.
I'm just trying to show the most important thing's.
I can save and reload this class without problems from my database.
[Serializable]
public class MainElement : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public static int count = 0;
[PrimaryKey]
public int Id { get; set; }
public string Name { get; set; }
public byte[] _elements;
private ObservableCollection<SecondElement> elements;
[OneToMany]
public ObservableCollection<SecondElement> Elements
{
get
{
return elements;
}
set
{
elements = value;
this.SerializeElementsFromMainElement();
//_elements = ExtensionAndDb.SerializeElementsFromMainElement(elements);
OnPropertyChanged();
}
}
public MainElement()
{
Id = count++;
Elements = new ObservableCollection<SecondElement>();
this.DeSerializeElementsFromMainElement();
//Elements = ExtensionAndDb.DeSerializeElementsFromMainElement(_elements);
}
public void OnPropertyChanged([CallerMemberName] string propertyname = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyname));
}
public void DeSerializeElementsFromMainElement()
{
BinaryFormatter bf = new BinaryFormatter();
MemoryStream stream = new MemoryStream(_elements);
using (stream)
{
Elements = bf.Deserialize(stream) as ObservableCollection<SecondElement>;
}
}
public void SerializeElementsFromMainElement()
{
BinaryFormatter bf = new BinaryFormatter();
MemoryStream stream = new MemoryStream();
using (stream)
{
bf.Serialize(stream, Elements);
_elements = stream.ToArray();
}
}
}
Every MainElement is stored in the MainList (ObservableCollection).
Everything is fine.
But i cant save or reload the public byte[] _elements; from/to the collection.
I know my code is not good, but if anyone has an idea or can show me how to save the public ObservableCollection<SecondElement> Elements with my class together in Sqlite, i would be really grateful.
I've been trying for 3 days
if you need more code, let me know.
Thank's in advance.
According to your description, you want to serialize and deserialie ObservableCollection, I suggest you ca use Newtonsoft.Json to do this.
Installing Newtonsoft.Json by Nuget package firstly.
For example, I do one esample:
public class person
{
public string username { get; set; }
public int age { get; set; }
}
public ObservableCollection<person> persons { get; set; }
private string list;
public Page13()
{
InitializeComponent();
persons = new ObservableCollection<person>()
{
new person(){username="cherry",age=12},
new person(){username="barry",age=14}
};
}
Btn1.clicked is to serialize data, Btn2.clicked is to deserialize data.
private void Btn1_Clicked(object sender, EventArgs e)
{
list = Newtonsoft.Json.JsonConvert.SerializeObject(persons);
}
private void Btn2_Clicked(object sender, EventArgs e)
{
var myValue = Newtonsoft.Json.JsonConvert.DeserializeObject<ObservableCollection<person>>(list) ;
}
If the Observablecollection changed, you can query this data by Id or other, then update this data.
Here is the article about Update, insert and save data in sqlite, you can take a look:
https://dzone.com/articles/register-and-login-using-sqlite-in-xamarinforms

xamarin sqlite SQLiteException: near ")": syntax error add

I am trying to learn xaml and C# used in Xamarin Forms, and now I want to implement SQLite functionality.
I am simply trying to add a value into a SQL table but get the following error:
Unhandled Exception:
SQLite.SQLiteException: near ")": syntax error occurred
My Database connection interface is as follows:
using SQLite;
namespace TestSQLite
{
public interface IDatabaseConnection
{
SQLiteAsyncConnection GetConnection();
}
}
My Android specific Database Connection (iOS is identical) is as follows:
using SQLite;
using System.IO;
using TestSQLite;
using Xamarin.Forms;
[assembly: Dependency(typeof(DatabaseConnection))]
namespace TestSQLite
{
public class DatabaseConnection : IDatabaseConnection
{
public SQLiteAsyncConnection GetConnection()
{
var dbName = "TestDb.db3";
var path = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), dbName);
return new SQLiteAsyncConnection(path);
}
}
}
My MainPage (testpage) is as follows:
using SQLite;
using Xamarin.Forms;
namespace TestSQLite
{
public class ControlledDrugs
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string Drug { get; set; }
public double Volume { get; set; }
}
public class Users
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string Name { get; set; }
}
public partial class MainPage : ContentPage
{
private SQLiteAsyncConnection _connection;
public MainPage()
{
InitializeComponent();
_connection = DependencyService.Get<IDatabaseConnection>().GetConnection();
}
protected override async void OnAppearing()
{
await _connection.CreateTableAsync<ControlledDrugs>();
await _connection.CreateTableAsync<Users>();
var drugs = await _connection.Table<ControlledDrugs>().ToListAsync();
Drugslistview.ItemsSource = drugs;
var user = await _connection.Table<Users>().ToListAsync();
Userlistview.ItemsSource = user;
base.OnAppearing();
}
async void OnAdd(object sender, System.EventArgs e)
{
var user = UserInput.Text;
//The next step generates the error
await _connection.InsertAsync(user);
}
void OnUpdate(object sender, System.EventArgs e)
{
}
void OnDelete(object sender, System.EventArgs e)
{
}
}
}
As you can see, I have yet to progress to update or delete. Learning by Youtube and Stackoverflow snippets is painfully slow. But this error got me stumped.
Also, have NuGet package sqlite-net-pcl v1.5.166-beta installed Xamarin Visual Studio.
you are attempting to insert a string into the User table instead of a User object
var user = UserInput.Text;
// user is just a string
await _connection.InsertAsync(user);
instead you need to create a User object
var user = new Users { Name = UserInput.Text };
await _connection.InsertAsync(user);

Web Api with OData v4 throwing exception on $select

I'm using the latest version of WebApi and OData and everything is set up to work right. The only problem is when I try to use $select .
It throws the error bellow
Object of type 'System.Linq.EnumerableQuery`1[System.Web.OData.Query.Expressions.SelectExpandBinder+SelectAll`1[WebApplication1.Controllers.Person]]' cannot be converted to type 'System.Collections.Generic.IEnumerable`1[WebApplication1.Controllers.Person]'.
I looked at the documentation and their suggestion is to use [Queryable] on top of the Get method in the controller or the in WebApiConfig to use config.EnableQuerySupport and neither of these are available options. I'm currently using [EnableQuery]
EDIT
OdataController:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.OData;
using System.Xml.Serialization;
namespace WebApplication1.Controllers
{
public class PeopleController : ODataController
{
// GET api/values
[EnableQuery]
public IQueryable<Person> Get()
{
return new Person[] { new Person()
{
Id = 1,
FirstName = "Testing",
LastName = "2"
}, new Person()
{
Id = 2,
FirstName = "TestTest",
LastName = "3"
} }.AsQueryable();
}
// GET api/values/5
public Person Get(int id)
{
return new Person()
{
Id = 3,
FirstName = "Test",
LastName = "1"
};
}
// POST api/values
public void Post([FromBody]Person value)
{
}
// PUT api/values/5
public void Put(int id, [FromBody]Person value)
{
}
// DELETE api/values/5
public void Delete(int id)
{
}
}
public class Person
{
[Key]
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
}
WebApiConfig
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
using System.Web.OData;
using System.Web.OData.Builder;
using System.Web.OData.Extensions;
using System.Web.OData.Formatter;
using WebApplication1.Controllers;
namespace WebApplication1
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
var odataFormatters = ODataMediaTypeFormatters.Create();
config.Formatters.InsertRange(0, odataFormatters);
ODataModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Person>("People");
config.AddODataQueryFilter();
config.MapODataServiceRoute(
routeName: "ODataRoute",
routePrefix: "api",
model: builder.GetEdmModel());
}
}
}
UPDATE 2
seems to only throw an error retrieving the data in xml format. Json seems to work
This is a known limitation of the XmlMediaTypeFormatter class from the System.Net.Formatting Nuget package. The implementation of the JSON formatter does support the $select and $expand commands but these are not available when content negotiation determines that XML should be returned.
You should look into implementing OData endpoints (as opposed to WebAPI endpoints) should you need to return XML formatted responses. More information on how this can be done can be found here:
http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/supporting-odata-query-options
Found a solution. It isn't perfect but it does work!
Maybe it will be useful for someone because I've spent on it few hours of research and trying.
Step #1 create custom xml formatter:
public class CustomXmlFormatter : MediaTypeFormatter
{
private JsonMediaTypeFormatter jFormatter = null;
public CustomXmlFormatter(JsonMediaTypeFormatter jFormatter)
{
SupportedMediaTypes.Add(new System.Net.Http.Headers.MediaTypeHeaderValue("application/xml"));
this.jFormatter = jFormatter;
}
public override bool CanReadType(Type type)
{
return false;
}
public override bool CanWriteType(Type type)
{
return true;
}
public override Task WriteToStreamAsync(Type type, object value, System.IO.Stream writeStream, System.Net.Http.HttpContent content, System.Net.TransportContext transportContext)
{
return Task.Factory.StartNew(() =>
{
using (MemoryStream ms = new MemoryStream())
{
var tsk = jFormatter.WriteToStreamAsync(type, value, ms, content, transportContext);
tsk.Wait();
ms.Flush();
ms.Seek(0, SeekOrigin.Begin);
var xDoc = XDocument.Load(JsonReaderWriterFactory.CreateJsonReader(ms, new XmlDictionaryReaderQuotas()));
using (XmlWriter xw = XmlWriter.Create(writeStream))
{
xDoc.WriteTo(xw);
}
}
});
}
}
Step #2 register it in startup section:
var formatters = ODataMediaTypeFormatters.Create();
var jsonFormatter = config.Formatters.JsonFormatter;
var customXmlFormatter = new CustomXmlFormatter(jsonFormatter);
customXmlFormatter.AddQueryStringMapping("$format", "cxml", "application/xml");
config.Formatters.Add(customXmlFormatter);
use it as
http://url..../actionName?$format=cxml&$select=ObjectName,ObjectId

Resources