How might I construct a non-default constructor model from a query string in ASP.Net Core? - asp.net-core

I would like to construct an object that has a non-default constructor from query string parameters in ASP.Net Core. In essence, I have two models that have a common ancestor class with different parameterizations. Based on some conditions in an API endpoint, one model will be constructed with parameters from the query string.
[HttpGet("{model}")]
public ModelBase Get(string model)
{
switch (model)
{
case "foo":
ModelFoo foo = GetModelFromQueryString<ModelFoo>();
return foo;
case "bar":
ModelBar bar = GetModelFromQueryString<ModelBar>();
return bar;
}
return null;
}
GetModelFromQueryString<TModel> is obviously the magical function that I wish I knew existed. If it already exists or someone could help provide implementation details, that would answer my question.
The example model classes would be like the following:
class ModelFoo : ModelBase
{
public ModelFoo(int param1=1, int param2=2)
{
// ...
}
}
class ModelBar : ModelBase
{
public ModelBar(int paramBaz=3)
{
// ...
}
}
This would ideally make the following HTTP calls yield the desired results:
GET api/foo?param1=7&param2=9 yields new ModelFoo(param1:7, param2:9).
GET api/bar?paramBaz=42 yields new ModelBar(paramBaz:42).
GET api/foo yields new ModelFoo(param1:1, param2:2).
GET api/foo?param2=11 yields new ModelFoo(param1:1, param2:11).
How might I go about this? Should I restructure entirely?
I realize that this may be a bit of a complicated, multi-faceted question so any and all help is much appreciated!

You can try to use my working demo.
Class:
public class ModelBase
{
}
class ModelFoo : ModelBase
{
public int param1 { get; set; }
public int param2 { get; set; }
public ModelFoo(int param1 = 1, int param2 = 2)
{
this.param1 = param1;
this.param2 = param2;
}
}
class ModelBar : ModelBase
{
public int paramBaz { get; set; }
public ModelBar(int paramBaz = 3)
{
this.paramBaz = paramBaz;
}
}
Action:
[HttpGet("{model}")]
public ModelBase Get(string model,int param1,int param2,int paramBaz)
{
switch (model)
{
case "foo":
if(param1!=0 ^ param2!=0)
{
if(param1 != 0)
{
ModelFoo foo1 = new ModelFoo
{
param1 = param1,
};
return foo1;
}
if (param2 != 0)
{
ModelFoo foo2 = new ModelFoo
{
param2 = param2,
};
return foo2;
}
}
if (param1 == 0 && param2 == 0)
{
ModelFoo foo3 = new ModelFoo();
return foo3;
}
ModelFoo foo4 = new ModelFoo
{
param1 = param1,
param2 = param2,
};
return foo4;
case "bar":
if (paramBaz != 0)
{
ModelBar bar = new ModelBar
{
paramBaz = paramBaz,
};
return bar;
}
ModelBar bar1 = new ModelBar();
return bar1;
}
return null;
}

Not really a direct answer to your question, but the needed building blocks are already available.
Newtonsoft JSON.net supports creating types if the constructor parameter matches the property names and also supports creating instances of an interface if the concrete type is set within a $type property:
public static class Program
{
public static async Task<int> Main(string[] args)
{
var sourceList = new List<IModel> { new ModelFoo(3, 7), new ModelBar(11) };
var jsonList = JsonConvert.SerializeObject(sourceList, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto });
var list = JsonConvert.DeserializeObject<List<IModel>>(jsonList, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto });
return 0;
}
}
public interface IModel { }
public class ModelFoo : IModel
{
public ModelFoo(int first, int second)
{
First = first;
Second = second;
}
public int First { get; }
public int Second { get; }
}
public class ModelBar : IModel
{
public ModelBar(int third)
{
Third = third;
}
public int Third { get; }
}

Related

Setting up examples in Swagger

I am using Swashbuckle.AspNetCore.Swagger (1.0.0) and Swashbuckle.AspNetCore.SwaggerGen (1.0.0). I am trying to add default examples to my API following Default model example in Swashbuckle (Swagger). I created a new class file and added,
public class SwaggerDefaultValue : Attribute
{
public string ParameterName { get; set; }
public string Value { get; set; }
public SwaggerDefaultValue(string parameterName, string value)
{
this.ParameterName = parameterName;
this.Value = value;
}
}
public class AddDefaultValues : IOperationFilter
{
public void Apply(Operation operation, DataTypeRegistry dataTypeRegistry, ApiDescription apiDescription)
{
foreach (var param in operation.Parameters)
{
var actionParam = apiDescription.ActionDescriptor.GetParameters().First(p => p.ParameterName == param.Name);
if (actionParam != null)
{
var customAttribute = actionParam.ActionDescriptor.GetCustomAttributes<SwaggerDefaultValue>().FirstOrDefault();
if (customAttribute != null)
{
param.DefaultValue = customAttribute.Value;
}
}
}
}
}
but I get this error - AddDefaultValues does not implement interface member IOperationFilter.Apply(Operation, OperationFilterContext)
That link you are following is not for the Swashbuckle.AspNetCore version
Look in the correct project for the proper examples:
https://github.com/domaindrivendev/Swashbuckle.AspNetCore/search?q=IOperationFilter&unscoped_q=IOperationFilter

Xamarin SQLite database creating for all tables

I have working on this topic for 4 hours but I couldn't get any solution.
My problem is actually;
I have 5 table and I wanna create one controller to create different tables.
My current codes are below but this codes create only one table.
public interface ISQLite
{
SQLiteConnection GetConnection();
}
-
public class TodoItem
{
public TodoItem ()
{
}
[PrimaryKey, AutoIncrement]
public int ID { get; set; }
public string Name { get; set; }
public string Notes { get; set; }
public bool Done { get; set; }
}
-
public class TodoItemDatabase
{
static object locker = new object ();
SQLiteConnection database;
/// <summary>
/// Initializes a new instance of the <see cref="Tasky.DL.TaskDatabase"/> TaskDatabase.
/// if the database doesn't exist, it will create the database and all the tables.
/// </summary>
/// <param name='path'>
/// Path.
/// </param>
public TodoItemDatabase()
{
database = DependencyService.Get<ISQLite> ().GetConnection ();
// create the tables
database.CreateTable<TodoItem>();
}
public IEnumerable<TodoItem> GetItems ()
{
lock (locker) {
return (from i in database.Table<TodoItem>() select i).ToList();
}
}
public IEnumerable<TodoItem> GetItemsNotDone ()
{
lock (locker) {
return database.Query<TodoItem>("SELECT * FROM [TodoItem] WHERE [Done] = 0");
}
}
public TodoItem GetItem (int id)
{
lock (locker) {
return database.Table<TodoItem>().FirstOrDefault(x => x.ID == id);
}
}
public int SaveItem (TodoItem item)
{
lock (locker) {
if (item.ID != 0) {
database.Update(item);
return item.ID;
} else {
return database.Insert(item);
}
}
}
public int DeleteItem(int id)
{
lock (locker) {
return database.Delete<TodoItem>(id);
}
}
}
-
public class SQLite_Android : ISQLite
{
public SQLite_Android()
{
}
#region ISQLite implementation
public SQLite.SQLiteConnection GetConnection()
{
var sqliteFilename = "TodoSQLite.db3";
string documentsPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal); // Documents folder
var path = Path.Combine(documentsPath, sqliteFilename);
// This is where we copy in the prepopulated database
Console.WriteLine(path);
if (!File.Exists(path))
{
var s = Forms.Context.Resources.OpenRawResource(Resource.Raw.TodoSQLite); // RESOURCE NAME ###
// create a write stream
FileStream writeStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write);
// write to the stream
ReadWriteStream(s, writeStream);
}
var conn = new SQLite.SQLiteConnection(path);
// Return the database connection
return conn;
}
#endregion
/// <summary>
/// helper method to get the database out of /raw/ and into the user filesystem
/// </summary>
void ReadWriteStream(Stream readStream, Stream writeStream)
{
int Length = 256;
Byte[] buffer = new Byte[Length];
int bytesRead = readStream.Read(buffer, 0, Length);
// write the required bytes
while (bytesRead > 0)
{
writeStream.Write(buffer, 0, bytesRead);
bytesRead = readStream.Read(buffer, 0, Length);
}
readStream.Close();
writeStream.Close();
}
}
--- How can I create multi tables in one controller ?
Looks like you are using Sqlite.net-pcl, right?
Multiple tables from the same model are not supported (it's for simple cases only).
You can create multiple models (possibly by just inheriting) and then call CreatTable<T> for each of them.
I solved problem. Maybe this solution helps somenone.
I have two DbHepler Class and two model class for creating two tables on DB.
Base connection codes are same;
public interface ISQLite
{
SQLiteConnection GetConnection();
}
This is the App.cs file;
public class App : Application {
public App()
{
authenticationDB = new AuthenticationDbHelper(Database);
settingsDbHelper = new SettingsDbHelper(Database);
MainPage = new Views.MainMenuPage();
}
public static CreateDB Database
{
get
{
if (database == null)
{
database = new CreateDB();
}
return database;
}
}
}
The CreateDB class is necessary for create one db for all tables
public class CreateDB
{
public SQLiteConnection database;
public object locker = new object();
public CreateDB()
{
database = DependencyService.Get<ISQLite>().GetConnection();
}
}
This interface is necessary for created tables actions. Since implement this class we can use theese methods all tables.(T is table class)(To understand look AuthenticationDBHelper class)
public interface SQLiteBase<T>
{
IEnumerable<T> GetItems();
T GetItem(long id);
long SaveItem(T item);
void UpdateItem(T item);
int DeleteItem(int id);
int Clear();
int getCount();
}
This DbHelper class will be used for delete,insert,clear.... items.
public class AuthenticationDbHelper : SQLiteBase<AuthenticationDbTable>
{
SQLiteConnection database;
object locker;
public AuthenticationDbHelper(CreateDB db)
{
database = db.database;
locker = db.locker;
database.CreateTable<AuthenticationDbTable>();
}
public int Clear()
{
lock(locker)
{
return database.DeleteAll<AuthenticationDbTable>();
}
}
public int DeleteItem(int id)
{
lock (locker)
{
return database.Delete<AuthenticationDbTable>(id);
}
}
public AuthenticationDbTable GetItem(long id)
{
lock (locker)
{
return database.Table<AuthenticationDbTable>().FirstOrDefault(x => x.UserId == id);
}
}
public IEnumerable<AuthenticationDbTable> GetItems()
{
lock (locker)
{
return (from i in database.Table<AuthenticationDbTable>() select i).ToList();
}
}
public long SaveItem(AuthenticationDbTable item)
{
lock (locker)
{
return database.Insert(item);
}
}
public void UpdateItem(AuthenticationDbTable item)
{
lock(locker)
{
database.Update(item);
}
}
public int getCount()
{
return GetItems().Count();
}
}
I know it is very confused but this is the last. We will create model for authentication.
public class AuthenticationDbTable
{
public AuthenticationDbTable(long userId, string sessionId, string username, string clientuuid)
{
this.userId = userId;
this.sessionId = sessionId;
this.username = username;
this.clientuuid = clientuuid;
}
private long userId;
private string sessionId;
private string username;
private string clientuuid;
[PrimaryKey]
public long UserId
{
get { return userId; }
set { userId = value; }
}
public string SessionId
{
get { return sessionId; }
set { sessionId = value; }
}
public string Username
{
get { return username; }
set { username = value; }
}
public string Clientuuid
{
get { return clientuuid; }
set { clientuuid = value; }
}
}
Using
AuthenticationDbTable authentication = new AuthenticationDbTable(authenticateduser.User.UserId, r.Retval.SessionStatus.SessionId, authenticateduser.User.Name, authenticateduser.Clientuuid);
App.authenticationDB.SaveItem(authentiaction);
Note
For creating second table you can use same way. You should create second DbHelper and model class. Assume that you will create a table for settings. You should create SettingsDbHelper and SettingsDbTable class. through same way.
Thank you :)

Tweak jackson polymorphic deserialization

I have a simple polymorphic model like this
public class Foo {
private Bar bar1;
private Bar bar2;
public Bar getBar1() {
return bar1;
}
public Bar getBar2() {
return bar2;
}
public void setBar1(Bar bar1) {
this.bar1 = bar1;
}
public void setBar2(Bar bar2) {
this.bar2 = bar2;
}
}
#JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "#type")
public class Bar {
}
public class BarExpression extends Bar {
private String expression;
public String getExpression() {
return expression;
}
#JsonIgnore
public Object getValue() {
return null;
}
public void setExpression(String expression) {
this.expression = expression;
}
}
public class BarLiteral extends Bar {
private String value;
private String type;
public String getType() {
return type;
}
public Object getValue() {
return value;
}
public void setType(String type) {
this.type = type;
}
public void setValue(String value) {
this.value = value;
}
}
Serializing a simple example like this
public void run() throws Exception {
Foo foo;
BarLiteral bar1;
BarExpression bar2;
//
foo = new Foo();
bar1 = new BarLiteral();
bar1.setType("java.lang.String");
bar1.setValue("gnu");
foo.setBar1(bar1);
bar2 = new BarExpression();
bar2.setExpression("bean.property * 2");
foo.setBar2(bar2);
//
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
StringWriter w = new StringWriter();
mapper.writeValue(w, foo);
System.out.println(w.toString());
}
gives the expected result:
{
"bar1" : {
"#type" : "de.mit.jackson.BarLiteral",
"value" : "gnu",
"type" : "java.lang.String"
},
"bar2" : {
"#type" : "de.mit.jackson.BarExpression",
"expression" : "bean.property * 2"
}
}
The question is now: I want to improve user experience when handwriting this "DSL" by supporting "primitive shortcuts" for the typed "Bar..." classes like this
{
"bar1" : "gnu",
"bar2" : "#{bean.property * 2}"
}
The solution that came closest was using a converter on Foo#bar1 and Foo#bar2, checking for either String or "Bar" input, but this solution requires decoration of every attribute definition.
Creating a deserializer with a comparable behavior did not work, as the #JsonTypeInfo is not compatible in the sense that i can have a #JsonDeserialize implementation that will check for a String event and then delegate to the standard #JsonTypeInfo process. The #JsonTypeInfo standard will check only for the #type and then delegate back to the (subtype) deserializer which is again my wrapper implementation.
The required process is
if input event is string {
parse and return string input
} else {
activate #type parsing delegate;
after #type parsing activate standard BeanDeserializer
(**not** my implementation)
}
Is there another hook i am missing?

NInject kernel GetAll returns empty

I've two projects (class library projects) which implement one interface:
The first one:
public class MailPlugin : Extensibility.IProductorPlugin
{
...
}
The second one:
public class FileSystemPlugin : Extensibility.IProductorPlugin
{
...
}
Extensibility.IProductorPlugin, is a interface of a third project:
namespace Extensibility
{
public delegate void NotifyDigitalInputs(List<Domain.DigitalInput> digital_inputs);
public interface IProductorPlugin
{
String Name { get; }
String Description { get; }
String Version { get; }
List<Domain.Channel> AvailableChannels { get; }
IEnumerable<Guid> TypeGuids { get; }
event NotifyDigitalInputs OnDigitalInputs;
}
}
In my composition root, I've created this class:
namespace UI
{
public sealed class NinjectServiceLocator
{
private static readonly Lazy<NinjectServiceLocator> lazy = new Lazy<NinjectServiceLocator>(() => new NinjectServiceLocator());
public static NinjectServiceLocator Instance { get { return lazy.Value; } }
public Ninject.IKernel Kernel { get; private set; }
private NinjectServiceLocator()
{
using (var k = this.Kernel = new Ninject.StandardKernel())
{
k.Bind(b => b.FromAssembliesMatching("*")
.SelectAllClasses()
.InheritedFrom(typeof(Extensibility.IProductorPlugin))
.BindAllInterfaces()
);
}
}
}
}
So, when I want to look for all plugins, I just perform this:
protected void initialize()
{
foreach (Extensibility.IProductorPlugin productor_plugin in NinjectServiceLocator.Instance.Kernel.GetAll(typeof(Extensibility.IProductorPlugin)))
{
using (var channel_tile = new DevExpress.XtraBars.Docking2010.Views.WindowsUI.Tile() { Group = "Plugin Channels" })
{
foreach (Domain.Channel channel in productor_plugin.AvailableChannels)
{
channel_tile.Elements.Add(new DevExpress.XtraEditors.TileItemElement() { Text = channel.Name });
channel_tile.Elements.Add(new DevExpress.XtraEditors.TileItemElement() { Text = channel.Description });
this.tileContainer1.Items.Add(channel_tile);
}
}
}
}
However, GetAll returns anything.
What am I doing wrong?
I'll appreciate a lot your help.
Thanks for all.
try removing the using() from around the Kernel instantiation. a using will dispose the object at the end of the scope, which we don't want for a kernel.
using (var k = this.Kernel = new Ninject.StandardKernel())

Value type field required in Razor View

I have an enum type field called Title.
[Serializable]
public enum Title
{
NotSet,
Miss = 4,
Mr = 1,
Mrs = 3,
Ms = 2
}
I want to bind a property of type Title to the Razor View but I don't want it to be a required field. However, on tabbing out or OnBlur, it is showing as required, although I have not specified this as required.
Is there any way I can get around this?
create
namespace YourApplicationName.Helper
{
public class ModelValueListProvider : IEnumerable<SelectListItem>
{
List<KeyValuePair<string, string>> innerList = new List<KeyValuePair<string, string>>();
public static readonly ModelValueListProvider TitleList = new TitleListProvider();
protected void Add(string value, string text)
{
string innerValue = null, innerText = null;
if (value != null)
innerValue = value.ToString();
if (text != null)
innerText = text.ToString();
if (innerList.Exists(kvp => kvp.Key == innerValue))
throw new ArgumentException("Value must be unique", "value");
innerList.Add(new KeyValuePair<string, string>(innerValue, innerText));
}
public IEnumerator<SelectListItem> GetEnumerator()
{
return new ModelValueListProviderEnumerator(innerList.GetEnumerator());
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
private struct ModelValueListProviderEnumerator : IEnumerator<SelectListItem>
{
private IEnumerator<KeyValuePair<string, string>> innerEnumerator;
public ModelValueListProviderEnumerator(IEnumerator<KeyValuePair<string, string>> enumerator)
{
innerEnumerator = enumerator;
}
public SelectListItem Current
{
get
{
var current = innerEnumerator.Current;
return new SelectListItem { Value = current.Key, Text = current.Value };
}
}
public void Dispose()
{
try
{
innerEnumerator.Dispose();
}
catch (Exception)
{
}
}
object System.Collections.IEnumerator.Current
{
get
{
return Current;
}
}
public bool MoveNext()
{
return innerEnumerator.MoveNext();
}
public void Reset()
{
innerEnumerator.Reset();
}
}
private class TitleListProvider : ModelValueListProvider
{
public TitleListProvider (string defaultText = null)
{
if (!string.IsNullOrEmpty(defaultText))
Add(string.Empty, defaultText);
Add(Title.NotSet, "NotSet");
Add(Title.Miss , "Miss");
Add(Title.Mr , "Mr");
Add(Title.Mrs , "Mrs");
Add(Title.MS, "MS");
}
public void Add(Title value, string text)
{
Add(value.ToString("d"), text);
}
}
}
}
in your model
public Title? Titleformation { get; set; }
public string[] SelectedTitle { get; set; }
in your view, also add the name space to your view
#using YourApplicationName.Helper;
#Html.ListBoxFor(m => m.SelectedTitle , new SelectList(ModelValueListProvider.TitleList, "Value", "Text"))
hope this help you
Enums require values, and cannot be null (aka not set) despite what someone commented above. What I do for salutations is have a "none" member of the enum, and whenever I print this out, I just check in the code to see if the value of the enum is > 0 (aka, the none option) and don't print it.
public enum Salutation { none,
[Description("Mr.")] Mr,
[Description("Mrs.")] Mrs,
[Description("Ms.")]Ms,
[Description("Miss")] Miss }
Use a class rather than enum ie:
public class Title
{
NotSet;
Miss = 4;
Mr = 1;
Mrs = 3;
Ms = 2;
}