Entity framework/MVC newbie here.
Writing my first EF application (api). So far so good, I can retrieve rows from the database but now I'm blocked by a problem which I can't wrap my head around.
I can't figure out how to manipulate the values returned. I retrieve a resultset with 5 columns and I want to encrypt the individual values before returning it to the calling app in a JSON string. Can anyone point me to an example on where in the code to achieve this? Model? Repository? I'm lost here.
namespace app.Models
{
public class ParameterSet
{
public int id { get; set; }
public string DbServerInstance { get; set; }
public string DbServerUser { get; set; }
public string DbServerPassword { get; set; }
public string DbServerDatabase { get; set; }
}
}
Connection context
namespace app.Repositories
{
public class DbconnectionContext : DbContext
{
public DbconnectionContext() : base("MobileAppsConnection")
{
Database.SetInitializer<DbconnectionContext>(null);
}
public DbSet<ParameterSet> ParameterSet { get; set; }
}
}
interface
namespace app.Repositories
{
interface IParameterSets
{
IEnumerable<ParameterSet> ListofParameterSet();
}
}
repository
namespace MobileAppsService.Repositories
{
public class ParameterSets : IParameterSets
{
public IEnumerable<ParameterSet> ListofParameterSet()
{
using (DbconnectionContext context = new DbconnectionContext())
{
var listofparameters = from parameters in context.ParameterSet
select parameters;
return listofparameters.ToList();
}
}
}
}
values controller
namespace MobileAppsService.Controllers
{
public class ValuesController : ApiController
{
readonly IParameterSets Iparamset;
public ValuesController()
{
Iparamset = new ParameterSets();
}
// GET api/values
public IEnumerable<ParameterSet> GetAlldata()
{
return Iparamset.ListofParameterSet();
}
}
}
You should manipulate the result set in the controller before returning it to the client. you don't have to make this data manipulation in the data layer.
namespace MobileAppsService.Controllers
{
public class ValuesController : ApiController
{
readonly IParameterSets Iparamset;
public ValuesController()
{
Iparamset = new ParameterSets();
}
// GET api/values
public IEnumerable<ParameterSet> GetAlldata()
{
var paramList = Iparamset.ListofParameterSet();
//do encryption of the paramlist here
//return the encrypted paramlist
return paramList;
}
}
}
Related
I've already searched, there are similar questions, but with JSON Array in answers they are using IConfigure in the controller. I can use IConfigure only in Startup.
I have this JSON Array in appsettings.json
{
"EmailList":[
{
"name":"John Algovich",
"email":"John.Algovich#mail.com"
},
{
"name":"Petr Algr",
"email":"Petr.Algr#mail.com"
},
{
"name":"Mathew Cena",
"email":"Mathew.Cena#mail.com"
}
]
}
EmailList.cs:
public class EmailAddress {
public string Name { get; set; }
public string Email { get; set; }
}
public class EmailList {
public List<EmailAddress> EmailArray { get; set; }
}
There is a lot of injections in Startup.cs, so I used the same code for mine:
services.Configure<EmailList>(Configuration.GetSection("EmailList"));
Controller:
public class DevController : Controller
{
private readonly EmailList _devEmailList;
private List<string> _emailList;
public DevController(
IOptions<EmailList> _devEmailList,
{
_devEmailList = devEmailList.Value;
_emailList = new List<string>();
}
}
public IActionResult Index()
{
var result = _devEmailList; // Returns null
var mailData2 = JsonConvert.DeserializeObject<EmailList>(_devEmailList.EmailArray.ToString()); // Returns null
}
Goal: How can get email adresses in Controller using Options and add it to the list?
Ok, so I was able to solve the problem:
I kept my appsettings.json the way it is with config classes.
I changed Startup code to this:
EmailInfo[] emails = Configuration.GetSection("EmailList").Get<EmailInfo[]>();
services.Configure<EmailList>(options => {options.EmailArray = emails.ToList();});
In my Controller:
This stays the same
public class DevController : Controller
{
private readonly EmailList _devEmailList;
private List<string> _emailList;
public DevController(
IOptions<EmailList> _devEmailList,
{
_devEmailList = devEmailList.Value;
_emailList = new List<string>();
}
}
Getting emails:
public IActionResult Index() {
var result = _udeEmailList.EmailArray;
foreach (var mailInfo in result)
{
emailsList.Add(mailInfo.Email);
}
}
what you are retrieving as your section is IEnumerable<EmailAddress> not EmailList. Read what you wrote, in your config there's no "EmailArray" definition.
You can add another level in your config (useful if you will have more things relative to email configuration in that section) or change the type to IEnumerable<EmailAddress> (not needed to be concretely IEnumerable, anything that implements it like an array or a list will work).
If you go for the first option you must do something like this:
In your config file...
{
"EmailConfig":{
"EmailList":[
{
"name":"John Algovich",
"email":"John.Algovich#mail.com"
},
{
"name":"Petr Algr",
"email":"Petr.Algr#mail.com"
},
{
"name":"Mathew Cena",
"email":"Mathew.Cena#mail.com"
}
]
//You can add here more properties
}
}
Your config classes:
public class EmailAddress
{
public string Name { get; set; }
public string Email { get; set; }
}
public class EmailConfig
{
public List<EmailAddress> EmailList { get; set; }
}
Your configuration:
services.Configure<EmailConfig>(Configuration.GetSection("EmailConfig"));
And the controller:
public class DevController : Controller
{
private readonly EmailConfig _mailConfig;
public DevController(IOptions<EmailConfig> mailConfig)
{
_mailConfig = mailConfig.Value;
}
public IActionResult Index()
{
var result = _mailConfig.EmailList;
}
}
I'd like to store LicenseInformations for multiple domains in my application.
The structure looks the following way:
public class LicenseData
{
// properties...
public List<LicenseDomain> Domains { get; set; }
// other properties...
}
public class LicenseDomain
{
// properties...
public object LicenseConfig { get; set; }
}
We have multiple domains with total different properties, but the license may contain multiple configurations..
For example:
{
"MaxValidUsers": 5
}
{
"Property": "xy"
"SubProperty": { "Foo" : "Bar"
}
}
The generation is no problem in any way..
But if I restore the informations from my signed json file I deserialize to object..
Which pattern / possiblity I have to work with Interfaces / Abstracts / that I can (RE)store generic informations here..
Right now I hack with:
JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(domain.LicenseConfig))
But I can't agree with myself.
So, based on the pieces of context I can grab, I would actually recommend having your LicenseConfig stored as a JSON string, which would give you the ability to do something like this:
public class LicenseDomain
{
// properties...
// Depending on how this is loaded,
// this property (or at least its setter) could be made private/protected/internal
public string LicenseConfigJson { get; set; }
public T LicenseConfig<T>() where T : BaseLicenseConfig
{
if (string.IsNullOrWhiteSpace(LicenseConfigJson))
{
return null;
}
return JsonConvert.DeserializeObject<T>(LicenseConfigJson);
}
public void SaveLicenseConfig<T>(T config) where T : BaseLicenseConfig
{
if (config == null)
{
LicenseConfigJson = null;
}
else
{
LicenseConfigJson = JsonConvert.SerializeObject(config);
}
}
}
Or if each LicenseDomain can only have one type of LicenseConfig, you could make it a generic parameter to the class:
public class LicenseData
{
// properties...
public List<LicenseDomain<BaseLicenseConfig>> Domains { get; set; }
// other properties...
}
public class LicenseDomain<T> where T : BaseLicenseConfig
{
// properties...
// Depending on where this value comes from, you could do this a variety of ways,
//but this is just one
public string LicenseConfigJson { get; set; }
public T LicenseConfig
{
get
{
if (string.IsNullOrWhiteSpace(LicenseConfigJson))
{
return null;
}
return JsonConvert.DeserializeObject<T>(LicenseConfigJson);
}
set
{
if (value == null)
{
LicenseConfigJson = null;
}
else
{
LicenseConfigJson = JsonConvert.SerializeObject(value);
}
}
}
}
public abstract class BaseLicenseConfig
{
}
public class LicConfig1 : BaseLicenseConfig
{
public int MaxValidUsers { get; set;}
}
public class LicConfig2 : BaseLicenseConfig
{
public string Property {get;set;}
public SubProp SubProperty {get;set;}
}
public class SubProp
{
public string Foo {get;set;}
}
In both cases, the BaseLicenseConfig class is strictly to enforce that everything in the domain list can come from a base class of some kind. If that's not important, you don't need the base class and can remove the where T : BaseLicenseConfig from LicenseDomain class.
Environment:
I am working in Webapi. There is 2 entity classes which are follows;
public class Class1
{
public Class1()
{
this.items = new HashSet<Class2>();
}
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Class2> items { get; set; }
}
public class Class2
{
public int Id { get; set; }
public string Name { get; set; }
public int Class1Id { get; set; }
public virtual Class1 class1 { get; set; }
}
Business Layer:
The buniess layer have the following codes;
public class Class1Logic : IClass1Logic
{
private readonly IClass1Repository _repo;
public Class1Logic(IClass1Repository repository)
{
_repo = repository;
}
public async Task<bool> AddClass1ItemAsync(Class1 item)
{
_repo.Add(item);
bool status = await _repo.SaveAsync();
return status;
}
public async Task<Class1> GetClass1ItemAsync(int id)
{
return await _repo.GetAsync(id);
}
}
public class Class2Logic : IClass1Logic
{
private readonly IClass2Repository _repo;
public Class2Logic(IClass2Repository repository)
{
_repo = repository;
}
public async Task<bool> AddClass2ItemAsync(Class2 item)
{
_repo.Add(item);
bool status = await _repo.SaveAsync();
return status;
}
public async Task<Class2> GetClass2ItemAsync(int id)
{
return await _repo.GetAsync(id);
}
}
ViewModels:
public class Class1Model
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Class2Model
{
public int Id { get; internal set; }
public string Name { get; set; }
public int Class1Id { get; set; }
public string Class1Name { get; internal set; }
}
Controllers:
There are 2 contrtollers like Class1Controller and Class2Controller. Both have all CRUD operations.
[RoutePrefix("api/class1items")]
public class Class1Controller : ApiController
{
private readonly IClass1Logic _class1Logic;
private ModelFactory TheFactory;
public Class1Controller(IClass1Logic class1Logic)
{
_class1Logic = class1Logic;
TheFactory = new ModelFactory();
}
[Route("")]
public async Task<IHttpActionResult> Post(Class1Model class1Model)
{
var item = TheFactory.Parse(class1Model);
bool result = await _class1Logic.AddClassItemAsync(item);
if (!result)
{
return BadRequest("Error");
}
string uri = Url.Link("GetLabById", new { id = item.Id });
return Created(uri, TheFactory.Create(item));
}
[Route("{id:int}", Name = "GetClass1ItemById")]
public async Task<IHttpActionResult> GetClass1Item(int id)
{
Class1 item = await _class1Logic.GetClassItemAsync(id);
if (item == null)
{
return NotFound();
}
return Ok(TheFactory.Create(item));
}
}
[RoutePrefix("api/class2items")]
public class Class2Controller : ApiController
{
private readonly IClass2Logic _class2Logic;
private ModelFactory TheFactory;
public Class2Controller(IClass2Logic class2Logic)
{
_class2Logic = class2Logic;
TheFactory = new ModelFactory();
}
[Route("")]
public async Task<IHttpActionResult> Post(Class2Model class2Model)
{
var item = TheFactory.Parse(class2Model);
***//Here item should include Class1 object even if user give ClassId in class2Model***
bool result = await _class2Logic.AddClassItemAsync(item);
if (!result)
{
return BadRequest("Error");
}
string uri = Url.Link("GetClass2ItemById", new { id = item.Id });
return Created(uri, TheFactory.Create(item));
}
}
There is not dependecies in Class1. So all operations are fine. In Class2Controller post method, I got the model object as following to create Class2.
{
"id": 0,
"name": "string",
"class1Id": 1
}
Understanding:
I need to return this viewmodel to user after the create the record. The record created successfully but when mapping to viewmodel i got null exception as Class1 object not in the Class2 object.
In order to get the Class2 object including class1 object, I need to give the class1Object in the request object.
For this i need to find the Class1 object with Class1Id in the request object.
ViewMapper Code:
public class ModelFactory
{
public Class1Model Create(Class1 item)
{
return new Class1Model
{
Id = item.Id,
Name = item.Name
};
}
public Class2Model Create(Class2 item)
{
return new Class2Model
{
Id = item.Id,
Name = item.Name,
Class1Id = item.class1.Id,
Class1Name = item.class1.Name
};
}
public Class1 Parse(Class1Model modelItem)
{
return new Class1
{
Id = modelItem.Id,
Name = modelItem.Name
};
}
public Class2 Parse(Class2Model modelItem)
{
return new Class2
{
Id = modelItem.Id,
Name = modelItem.Name,
Class1Id = modelItem.Class1Id,
***/*Issue Place*/
//class1 = Need to set property by getting object using modelItem.Class1Id***
};
}
}
Issue:
Now i need to call get method of Class1Controller by passing Class1Id.
How to call and is this correct? or my design is bad?
This is initial case. If my Class3 have both Class1 and Class2 again i need to call methods of Class1 and Class2.
Please help to find the correct solution in this case
Note: I added comments the issue area to understand
Well, just to fix this issue you need to manually call _class1Logic.GetClass1ItemAsync after saving. However this doesn't look good.
More elegant ways to fix it:
1) If you always need Class2.Class1 field to be filled use Include when you fetch data (in repository): dbContext.Set<Class2>().Include(c => c.class1).
2) Also you can turn on LazyLoading for EF - I assume it should work in your case.
3) Inject class1Repo to class2Logic and fix up class1 reference after saving - in case if you don't want to enable lazy loading or item was detached from context after save method
Thoughts about design:
I suggest you to look at Automapper or simular libraries instead of ModelFactory where you going to have all mapping logic
Edit: About generic repository: you can modify you GetAsync method
public async Task<T> GetAsync<T>(int id, params Expression<Func<T, object>>[] includes)
where T: class, IEntity
{
var query = context.Set<T>().AsQueryable();
if (includes.Length > 0)
{
query = includes.Aggregate(query,
(current, include) => current.Include(include));
}
return await query.FirstOrDefaultAsync(x => x.Id == id);
}
IEntity interface:
interface IEntity
{
int Id { get; }
}
With this implementation you can use
await _repo.GetAsync<Class2>(id, x => x.class1);
I am new to generics and just wondering if it's possible to avoid the casting in the following code using better OO approach.
public class CollectorFactory
{
public static MyCollector Create(ICredential credential)
{
return new MyCollector(credential);
}
}
public class MyCollector {
public MyCredential Credential { get; set; }
public MyCollector(ICredential credential)
{
this.Credential = (MyCredential)credential;
}
public void Show()
{
Console.WriteLine(this.Credential.Username);
Console.WriteLine(this.Credential.AuthToken);
}
}
public class MyCredential : ICredential
{
public string Username{ get; set; }
public string AuthToken { get; set; }
}
public interface ICredential
{
}
Is there a way to save the casting of ICredential to MyCredential in MyCollector's Constructor? I don't have option to put Username and AuthToken in ICredential as it's implemented by two different Credentials that both have different set of properties. CollectorFactory will be returning different MyCollector instances in the future and both need to have different credentials.
Any help would be really appreciated.
I don't think it's possible given that you're implementing different credentials and trying to use them for ICredential as well.
Here is a way of doing this using generics. Please read my comments in the code.
public class CollectorFactory<T>
{
public T Create(ICredential credential)
{
return (T)Activator.CreateInstance(typeof(T), credential);
}
}
public class MyCollector : BaseCollector
{
public dynamic Credential { get; private set; }
public MyCollector(ICredential credential)
: base(credential)
{
this.Credential = credential;
}
// Having this method here limits your ability to make it more generic.
// Consider moving this to MyCredential since it refers to specific properties in MyCredential.
// If that is not what you want, then you must do a type check before calling methods/ accessing props in Credentials.
public void Show()
{
Console.WriteLine(this.Credential.Username);
Console.WriteLine(this.Credential.AuthToken);
}
}
public class MyCredential : ICredential
{
public string Username { get; set; }
public string AuthToken { get; set; }
}
public abstract class BaseCollector : ICredentialCollector
{
protected BaseCollector(ICredential credential)
{
if (credential == null)
{
throw new ArgumentNullException(nameof(credential));
}
}
}
public interface ICredentialCollector
{
}
public interface ICredential
{
}
// test implementation
public class TestClass
{
public void AuthFactoryTest()
{
// test auth instance
MyCredential auth = new MyCredential() {AuthToken = "asfgasdgdfg", Username = "xuser"};
// Create test factory
var fact = new CollectorFactory<MyCollector>();
var myCollector = fact.Create(auth);
// Do what you need to do to collector object
myCollector.Show();
}
}
Generics isn't the solution in this case. The issue here is that your factory is returning a specific type (MyCollector). A solution around this would be the following:
public class CollectorFactory
{
public static ICollector Create(MyCredential credential)
{
return new MyCollector(credential);
}
public static ICollector Create(OtherCredential credential)
{
return new OtherCollector(credential);
}
}
public interface ICollector
{
void Show();
}
public class MyCollector : ICollector
{
public MyCredential Credential { get; set; }
public MyCollector(MyCredential credential)
{
this.Credential = credential;
}
public void Show()
{
Console.WriteLine(this.Credential.Username);
Console.WriteLine(this.Credential.AuthToken);
}
}
public class MyCredential : ICredential
{
public string Username{ get; set; }
public string AuthToken { get; set; }
}
public interface ICredential
{
}
The above is pretty much the canonical example of the Factory design pattern.
Instead of overloads you could also do typechecking in the factory:
public class CollectorFactory
{
public static ICollector Create(ICredential credential)
{
if(credential.GetType() == typeof(MyCredential))
return new MyCollector((MyCredential) credential);
if(credential.GetType() == typeof(OtherCredential ))
return new OtherCollector((OtherCredential ) credential);
}
}
Hi
I have some problems in import scenarios example:
[Export(typeof(IICon))]
public class WriteInputData : IICon
{
[Import(typeof(IIOWriter))]
public IIOWriter IOWriter { get; set; }
public object Input { get; set; }
public void Process()
{
IOWriter.Write(Input);
}
}
Then i hawe two classes that implement interface IIOWriter like :
[Export(typeof(IIOWriter))]
public class FileWriter : IIOWriter
{
public string FilePath { get; set; }
public void Write(object data)
{
if (string.IsNullOrEmpty(FilePath))
FilePath = #"c:\test.txt";
var fl = new StreamWriter(FilePath, true);
fl.Write((string)data);
fl.Flush();
fl.Close();
}
public string Name
{
get { return "FileWriter"; }
}
}
[Export(typeof(IIOWriter))]
public class ConsoleWrite : IIOWriter
{
public void Write(object data)
{
Console.WriteLine((string)data);
}
public string Name
{
get { return "ConsoleWrite"; }
}
}
How can i let that to user so he can change that in runtime, so example whene he type select in ListBox FileWriter than the IIOWriter in WriteInputData will be injected FileWriter end so one..
Sorry for my bad english.
You probably need to supply some metadata to the export, such like:
[Export(typeof(IIOWriter)),
ExportMetadata("Name", "ConsoleWriter")]
public class ConsoleWriter : IIOWriter
{
}
The reason you need to do this, is that you need to know ahead of time what the user selection will match to. Because of this, you may want to refactor your design to remove the dependency on the IOWriter property:
[Export(typeof(IICon))]
public class WriteInputData : IICon
{
public object Input { get; set; }
public void Process(IIOWriter writer)
{
}
}
If you define your Process method to take in an instance, we can resolve it using the CompositionContainer. Firstly, define a metadata interface that matches your ExportMetadata value:
public interface INamedMetadata
{
string Name { get; }
}
And then, we can resolve the instance:
public IIOWriter GetWriter(string name)
{
return container
.GetExports<IIOWriter, INamedMetadata>()
.Where(e => e.Metadata.Name.Equals(name, StringComparison.OrdinalIgnoreCase))
.Select(e => e.Value)
.FirstOrDefault();
}
Hope that points you in the right direction....