I have a project that has a login screen. When the user logs in the Controller calls another Class that I am using as a data Access class. This Class called the stored procedure to verify if the user is valid and pulls back all the user information and loads it into a UserModel. This works as I just have the data access method return a bool. So then I am logged in. But the information is not staying or is never stored in my model. I have been researching this and working off and on for this for weeks. I am hoping another set of eyes will help show me what I am missing. Thanks.
Here is my Model
public class UserModel
{
/// <summary>
/// Holds the current username.
/// </summary>
public string UserName {get;set;}
/// <summary>
/// Holds the First Name of the user.
/// </summary>
public string FirstName { get; set; }
/// <summary>
/// Holds the last name of the user.
/// </summary>
public string LastName { get; set; }
/// <summary>
/// Holds the users Date of Birth.
/// </summary>
public string UserDOB { get; set; }
/// <summary>
/// Holds the users Email Address
/// that was provided.
/// </summary>
public string Email { get; set; }
/// <summary>
/// Holds the current Password of the user.
/// </summary>
public string Password { get; set; }
/// <summary>
/// Holds the Date the account was created.
/// </summary>
public DateTime CreationDate { get; set; }
/// <summary>
/// Holds the PK of the type of user,
/// Admin, Standard, Promotional
/// </summary>
public int UserType { get; set; }
}
Here is my Data Access
public bool UserLogin(string userName, string Password)
{
bool userFound = false;
const string Query = #"GetUserLogin";
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
SqlCommand command = new SqlCommand(Query, connection)
{
CommandType = CommandType.StoredProcedure
};
command.Parameters.AddWithValue("#UserName", userName);
command.Parameters.AddWithValue("#Password", Password);
using (SqlDataReader reader = command.ExecuteReader())
{
reader.Read();
userModel.UserName = reader["UserName"].ToString();
userModel.FirstName = reader["FirstName"].ToString();
userModel.LastName = reader["LastName"].ToString();
userModel.Email = reader["Email"].ToString();
userModel.UserDOB = reader["UserDOB"].ToString();
if (reader == null)
{
userFound = false;
}
else
{
userFound = true;
}
}
}
return userFound;
}
This is my User Controller
public class UserController : Controller
{
private UserLoginDataAccess dataAccess = new UserLoginDataAccess();
// GET: /Login/
[HttpGet]
public IActionResult Login()
{
return View();
}
[HttpPost, ValidateAntiForgeryToken]
public IActionResult Login(UserModel model)
{
bool isLoggedIn;
isLoggedIn = dataAccess.UserLogin(model.UserName, model.Password);
if (isLoggedIn)
{
return View("Dashboard");
}
else
{
return View();
}
}
}
Firstly, this is never not null:
if (reader == null)
Secondly: where / how is userModel defined? If that is a field on the controller, then note that it jsn't persisted anywhere between requests. You need to use other approaches here. Usually an auth cookie of some kind.
Thirdly: I'm horrified to know whether you're doing a flat password compare in the DB; please let it be hashed...
Fourthly: writing your own security code is almost never a good idea. There are login providers that get it right. I recommend using them.
Fifthly: you should test whether Read() returned true or not - although frankly I think I'd recommend offloading all of this DB code to something like Dapper.
This is my setup for my .NET Core application:
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args)
{
return WebHost.CreateDefaultBuilder(args)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.ConfigureAppConfiguration((builderContext, config) =>
{
var entryAssemblyFolder = new FileInfo(Assembly.GetEntryAssembly().Location).DirectoryName;
IHostingEnvironment env = builderContext.HostingEnvironment;
config
.SetBasePath(entryAssemblyFolder)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
})
.UseStartup<Startup>()
.Build();
}
}
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public static IConfiguration Configuration { get; set; }
}
All of the above runs when the program starts. At a later point in time during the execution of the program, I'd like to be able to add additional configuration based on data which isn't known at startup time. The following is pseudo-code since there's no parameter to the ConfigurationBuilder constructor:
public class Helper
{
public void Add(string key, string value)
{
//pseudo-code:
var builder = new ConfigurationBuilder(Startup.Configuration);
builder.AddInMemoryCollection(new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>(key, value)
});
Startup.Configuration = builder.Build();
}
}
How can I add to the existing configuration, while keeping what's already there (including the reloadOnChange: true) ?
Thanks,
I did some more digging into the source of MemoryConfigurationProvider. The provider copies the initial data into it's own Data property.
So even if you update your original dictionary, the provider will still only have the original values, when it was initialized.
Haven't tried the GetReloadToken approach which might work, but here is an alternative more direct approach.
Consider this be your configuration:
public class MyConfiguration
{
public static Dictionary<string,string> InMemoryCollection =
new Dictionary<string, string>
{
{"InMemoryCollection:Option1", "value1"},
{"InMemoryCollection:Option2", "value2"}
};
}
Initialize your configuration:
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(builder => {
builder.AddInMemoryCollection(MyConfiguration.InMemoryCollection);
})
.UseStartup<Startup>();
Assume you have a controller to read and enter new values:
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
private IConfigurationRoot configuration;
/// <summary>
/// Initializes a new instance of the <see cref="ValuesController"/> class.
/// Value injected through DI.
/// </summary>
/// <param name="configuration">The configuration.</param>
public ValuesController(IConfiguration configuration)
{
this.configuration = (IConfigurationRoot)configuration;
}
[HttpGet]
/// <summary>
/// Get in memory values.
/// </summary>
/// <returns></returns>
public IDictionary<string,string> Get()
{
var result = new Dictionary<string, string>();
this.configuration.GetSection("InMemoryCollection").Bind(result);
return result;
}
[HttpPost]
/// <summary>
/// Enter a new value.
/// </summary>
/// <param name="value">The value.</param>
public void Post([FromBody] string value)
{
//get the provider instance from the configuration root.
MemoryConfigurationProvider memoryProvider =
(MemoryConfigurationProvider)this.configuration.Providers
.First(p =>
p.GetType() == typeof(MemoryConfigurationProvider));
//add the new option into the providers data collection.
var nextKey = MyConfiguration.InMemoryCollection.Count + 1;
memoryProvider.Add(
$"InMemoryCollection:Option{nextKey}",
value);
}
}
Note: I don't know the details/requirements for configuration options that are added dynamically, but using the AddInMemoryCollection approach doesn't look like it's the best of choices. Unless of course, you deliberately don't want to persist them.
I am fairly certain though that there are other approaches/solutions to resolve the issue, without necessarily using the Microsoft.Extensions.Configuration APIs.
Why on gods earth will the APFile.Id not deserialize correct ???
I have a simple class APFile - which I try to deserialize - for some reason it will not deserialize the Id - and I cannot see where its going wrong :(
using System;
using Newtonsoft.Json;
namespace ActionShared
{
[Serializable]
public class APFile
{
public APFile()
{
}
/// <summary>
/// File id
/// </summary>
[JsonProperty("id")]
public int Id { get; set; }
/// <summary>
/// The id of entity that the file is attached to.
/// </summary>
// [JsonProperty("type")]
[JsonIgnore]
public int Type { get; set; }
/// <summary>
/// The file name including the extension.
/// </summary>
[JsonProperty("filename")]
public string Filename { get; set; }
/// <summary>
/// The mime type of the file.
/// </summary>
[JsonIgnore]
public string Mimetype { get; set; }
/// <summary>
/// The size of the file in bytes.
/// </summary>
//[JsonProperty("size")]
[JsonIgnore]
public int Size { get; set; }
/// <summary>
/// The unique id of the file creator's profile.
/// </summary>
//[JsonProperty("creator_id")]
[JsonIgnore]
public int Creator { get; set; }
/// <summary>
/// The unique id of the file creator's profile.
/// </summary>
//[JsonProperty("creator_name")]
[JsonIgnore]
public string CreatorName { get; set; }
/// <summary>
/// The date and time when the file was uploaded.
/// </summary>
// [JsonProperty("created_at")]
[JsonIgnore]
public DateTime CreatedAt { get; set; }
/// <summary>
/// The date and time when the file was last updated.
/// </summary>
// [JsonProperty("updated_at")]
[JsonIgnore]
public DateTime UpdatedAt { get; set; }
/// <summary>
/// A link to download the file.
/// </summary>
//[JsonProperty("url")]
[JsonIgnore]
public string Url { get; set; }
}
}
public void Do()
{
string a = "{\"id\":910,\"filename\":\"image.jpg\"}";
var b = JsonConvert.DeserializeObject<APFile>(a);
// b.Id = 0 and b.Filename = "image.jpg"
}
plz copy your json responce and convert into C# class file to http://json2csharp.com/
public home()
{
InitializeComponent();
NavigationPage.SetHasNavigationBar(this, false);
PostRequest(this, "http://propertyworld.in/app/property.php?");
}
public async static void PostRequest(home instance, string URL)
{
var formContent = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("action", "property_list"),
});
var myHttpClient = new HttpClient();
var response = await myHttpClient.PostAsync(URL, formContent);
//json variable is over responce
var json = await response.Content.ReadAsStringAsync();
MyJsonConvertedclass record = JsonConvert.DeserializeObject<MyJsonConvertedclass>(json);
ObservableCollection<ModelClass.infoClass> ls = new ObservableCollection<ModelClass.infoClass> { };
foreach (var point in record.records)
{
ls.Add(new ModelClass.infoClass
{
info1 = Stringclass.rs + " " + point.property.price,
info2 = point.property.title.ToUpper(),
url = record.image_url + point.property.image
});
}
instance.newProp.ItemsSource = ls;
//instance.yourControllname which is declares in your xaml like
}
I have following JSON string which is received from an external party.
{
"team":[
{
"v1":"",
"attributes":{
"eighty_min_score":"",
"home_or_away":"home",
"score":"22",
"team_id":"500"
}
},
{
"v1":"",
"attributes":{
"eighty_min_score":"",
"home_or_away":"away",
"score":"30",
"team_id":"600"
}
}
]
}
My mapping classes:
public class Attributes
{
public string eighty_min_score { get; set; }
public string home_or_away { get; set; }
public string score { get; set; }
public string team_id { get; set; }
}
public class Team
{
public string v1 { get; set; }
public Attributes attributes { get; set; }
}
public class RootObject
{
public List<Team> team { get; set; }
}
The question is that I don't like the Attributes class name and the attributes field names in the Team class. Instead, I want it to be named TeamScore and also to remove _ from the field names and give proper names.
JsonConvert.DeserializeObject<RootObject>(jsonText);
I can rename Attributes to TeamScore, but if I change the field name (attributes in the Team class), it won't deserialize properly and gives me null. How can I overcome this?
Json.NET - Newtonsoft has a JsonPropertyAttribute which allows you to specify the name of a JSON property, so your code should be:
public class TeamScore
{
[JsonProperty("eighty_min_score")]
public string EightyMinScore { get; set; }
[JsonProperty("home_or_away")]
public string HomeOrAway { get; set; }
[JsonProperty("score ")]
public string Score { get; set; }
[JsonProperty("team_id")]
public string TeamId { get; set; }
}
public class Team
{
public string v1 { get; set; }
[JsonProperty("attributes")]
public TeamScore TeamScores { get; set; }
}
public class RootObject
{
public List<Team> Team { get; set; }
}
Documentation: Serialization Attributes
If you'd like to use dynamic mapping, and don't want to clutter up your model with attributes, this approach worked for me
Usage:
var settings = new JsonSerializerSettings();
settings.DateFormatString = "YYYY-MM-DD";
settings.ContractResolver = new CustomContractResolver();
this.DataContext = JsonConvert.DeserializeObject<CountResponse>(jsonString, settings);
Logic:
public class CustomContractResolver : DefaultContractResolver
{
private Dictionary<string, string> PropertyMappings { get; set; }
public CustomContractResolver()
{
this.PropertyMappings = new Dictionary<string, string>
{
{"Meta", "meta"},
{"LastUpdated", "last_updated"},
{"Disclaimer", "disclaimer"},
{"License", "license"},
{"CountResults", "results"},
{"Term", "term"},
{"Count", "count"},
};
}
protected override string ResolvePropertyName(string propertyName)
{
string resolvedName = null;
var resolved = this.PropertyMappings.TryGetValue(propertyName, out resolvedName);
return (resolved) ? resolvedName : base.ResolvePropertyName(propertyName);
}
}
Adding to Jacks solution. I need to Deserialize using the JsonProperty and Serialize while ignoring the JsonProperty (or vice versa). ReflectionHelper and Attribute Helper are just helper classes that get a list of properties or attributes for a property. I can include if anyone actually cares. Using the example below you can serialize the viewmodel and get "Amount" even though the JsonProperty is "RecurringPrice".
/// <summary>
/// Ignore the Json Property attribute. This is usefule when you want to serialize or deserialize differently and not
/// let the JsonProperty control everything.
/// </summary>
/// <typeparam name="T"></typeparam>
public class IgnoreJsonPropertyResolver<T> : DefaultContractResolver
{
private Dictionary<string, string> PropertyMappings { get; set; }
public IgnoreJsonPropertyResolver()
{
this.PropertyMappings = new Dictionary<string, string>();
var properties = ReflectionHelper<T>.GetGetProperties(false)();
foreach (var propertyInfo in properties)
{
var jsonProperty = AttributeHelper.GetAttribute<JsonPropertyAttribute>(propertyInfo);
if (jsonProperty != null)
{
PropertyMappings.Add(jsonProperty.PropertyName, propertyInfo.Name);
}
}
}
protected override string ResolvePropertyName(string propertyName)
{
string resolvedName = null;
var resolved = this.PropertyMappings.TryGetValue(propertyName, out resolvedName);
return (resolved) ? resolvedName : base.ResolvePropertyName(propertyName);
}
}
Usage:
var settings = new JsonSerializerSettings();
settings.DateFormatString = "YYYY-MM-DD";
settings.ContractResolver = new IgnoreJsonPropertyResolver<PlanViewModel>();
var model = new PlanViewModel() {Amount = 100};
var strModel = JsonConvert.SerializeObject(model,settings);
Model:
public class PlanViewModel
{
/// <summary>
/// The customer is charged an amount over an interval for the subscription.
/// </summary>
[JsonProperty(PropertyName = "RecurringPrice")]
public double Amount { get; set; }
/// <summary>
/// Indicates the number of intervals between each billing. If interval=2, the customer would be billed every two
/// months or years depending on the value for interval_unit.
/// </summary>
public int Interval { get; set; } = 1;
/// <summary>
/// Number of free trial days that can be granted when a customer is subscribed to this plan.
/// </summary>
public int TrialPeriod { get; set; } = 30;
/// <summary>
/// This indicates a one-time fee charged upfront while creating a subscription for this plan.
/// </summary>
[JsonProperty(PropertyName = "SetupFee")]
public double SetupAmount { get; set; } = 0;
/// <summary>
/// String representing the type id, usually a lookup value, for the record.
/// </summary>
[JsonProperty(PropertyName = "TypeId")]
public string Type { get; set; }
/// <summary>
/// Billing Frequency
/// </summary>
[JsonProperty(PropertyName = "BillingFrequency")]
public string Period { get; set; }
/// <summary>
/// String representing the type id, usually a lookup value, for the record.
/// </summary>
[JsonProperty(PropertyName = "PlanUseType")]
public string Purpose { get; set; }
}
Expanding Rentering.com's answer, in scenarios where a whole graph of many types is to be taken care of, and you're looking for a strongly typed solution, this class can help, see usage (fluent) below. It operates as either a black-list or white-list per type. A type cannot be both (Gist - also contains global ignore list).
public class PropertyFilterResolver : DefaultContractResolver
{
const string _Err = "A type can be either in the include list or the ignore list.";
Dictionary<Type, IEnumerable<string>> _IgnorePropertiesMap = new Dictionary<Type, IEnumerable<string>>();
Dictionary<Type, IEnumerable<string>> _IncludePropertiesMap = new Dictionary<Type, IEnumerable<string>>();
public PropertyFilterResolver SetIgnoredProperties<T>(params Expression<Func<T, object>>[] propertyAccessors)
{
if (propertyAccessors == null) return this;
if (_IncludePropertiesMap.ContainsKey(typeof(T))) throw new ArgumentException(_Err);
var properties = propertyAccessors.Select(GetPropertyName);
_IgnorePropertiesMap[typeof(T)] = properties.ToArray();
return this;
}
public PropertyFilterResolver SetIncludedProperties<T>(params Expression<Func<T, object>>[] propertyAccessors)
{
if (propertyAccessors == null)
return this;
if (_IgnorePropertiesMap.ContainsKey(typeof(T))) throw new ArgumentException(_Err);
var properties = propertyAccessors.Select(GetPropertyName);
_IncludePropertiesMap[typeof(T)] = properties.ToArray();
return this;
}
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
var properties = base.CreateProperties(type, memberSerialization);
var isIgnoreList = _IgnorePropertiesMap.TryGetValue(type, out IEnumerable<string> map);
if (!isIgnoreList && !_IncludePropertiesMap.TryGetValue(type, out map))
return properties;
Func<JsonProperty, bool> predicate = jp => map.Contains(jp.PropertyName) == !isIgnoreList;
return properties.Where(predicate).ToArray();
}
string GetPropertyName<TSource, TProperty>(
Expression<Func<TSource, TProperty>> propertyLambda)
{
if (!(propertyLambda.Body is MemberExpression member))
throw new ArgumentException($"Expression '{propertyLambda}' refers to a method, not a property.");
if (!(member.Member is PropertyInfo propInfo))
throw new ArgumentException($"Expression '{propertyLambda}' refers to a field, not a property.");
var type = typeof(TSource);
if (!type.GetTypeInfo().IsAssignableFrom(propInfo.DeclaringType.GetTypeInfo()))
throw new ArgumentException($"Expresion '{propertyLambda}' refers to a property that is not from type '{type}'.");
return propInfo.Name;
}
}
Usage:
var resolver = new PropertyFilterResolver()
.SetIncludedProperties<User>(
u => u.Id,
u => u.UnitId)
.SetIgnoredProperties<Person>(
r => r.Responders)
.SetIncludedProperties<Blog>(
b => b.Id)
.Ignore(nameof(IChangeTracking.IsChanged)); //see gist
I am using JsonProperty attributes when serializing but ignoring them when deserializing using this ContractResolver:
public class IgnoreJsonPropertyContractResolver: DefaultContractResolver
{
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
var properties = base.CreateProperties(type, memberSerialization);
foreach (var p in properties) { p.PropertyName = p.UnderlyingName; }
return properties;
}
}
The ContractResolver just sets every property back to the class property name (simplified from Shimmy's solution). Usage:
var airplane= JsonConvert.DeserializeObject<Airplane>(json,
new JsonSerializerSettings { ContractResolver = new IgnoreJsonPropertyContractResolver() });
Also if you want to ignore something use this
[JsonIgnore]
public int Id { get; set; }
[JsonProperty("id")]
Public string real_id { get; set; }
I am using entity framework code first with dotConnect for MySQL, and for some reason I get an error about one of my models mapping.
I've searched this error and it is usually caused by bad xml file or entity framework specific files. I am not using any of these, only a .cs code file with the models.
Exception Details:
System.Data.MappingException: The number of members in the conceptual
type 'SiteModels.TournamentTable' does not match with the number of
members on the object side type 'SiteModels.TournamentTable'. Make
sure the number of members are the same.
I have no idea why I am getting this error, since I don't have any designer,
only one file containing the code.
Here is the problematic class:
public class TournamentTable
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public List<TournamentColumn> Columns { get; set; }
public TournamentTable()
{
Columns = new List<TournamentColumn>();
}
public void AddColumn(int index, TournamentColumn column)
{
Columns.Insert(index, column);
}
public void RemoveColumn(int index)
{
Columns.RemoveAt(index);
}
/// <summary>
/// Add a tournament cell at the top of the column.
/// </summary>
/// <param name="column"></param>
public void AddColumn(TournamentColumn column)
{
Columns.Add(column);
}
/// <summary>
/// Returns the tournament column at the index specified.
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
public TournamentColumn this[int index]
{
get { return Columns[index]; }
}
/// <summary>
/// Returns the tournament cell at the index specified.
/// </summary>
/// <param name="columnIndex"></param>
/// <param name="cellIndex"></param>
/// <returns></returns>
public TournamentCell this[int columnIndex, int cellIndex]
{
get { return Columns[columnIndex][cellIndex]; }
set
{
Columns[columnIndex][cellIndex] = value;
}
}
}
Context configuration:
public class EntitiesContext : DbContext
{
public EntitiesContext()
: base()
{
System.Data.Entity.Database.SetInitializer<EntitiesContext>(new DropCreateDatabaseIfModelChanges<EntitiesContext>());
}
public EntitiesContext(DbConnection connection)
: base(connection, true)
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions
.Remove<System.Data.Entity.ModelConfiguration.Conventions
.ColumnTypeCasingConvention>();
}
public DbSet<User> Users { get; set; }
public DbSet<Player> Players { get; set; }
public DbSet<Game> Games { get; set; }
public DbSet<TournamentTable> TournamentTables { get; set; }
}
Thanks for the help, I don't have any clue.
Try commenting out the indexers and see if it helps. If it does you may need to put NotMapped attribute on them or reimplement them as methods.