I am attempting to call my model from my controller, but get errors. The error is on
new UserModels(id, searchcriteria);
and states that
UserModels does not contain a constructor that takes 2 arguments.
Any ideas?
Controller/Action:
public ActionResult ID(string id)
{
ViewBag.Message = "Customer Information";
string searchcriteria = "userid";
UserModels model = new UserModels(id, searchcriteria);
return View();
}
Model:
public class UserModels
{
public UserData user { get; set; }
public string firstname { get; set; }
public string lastname { get; set; }
public string searchvalue {get; set; }
public string searchcriteria { get; set; }
public List<UserData> UserModel(string id, string searchcriteria)
{
SSO_Methods sso = new SSO_Methods();
List<UserData> userObject = sso.GetUserObject(id, searchcriteria);
return userObject;
}
}
Constructors in c# cannot return anything.
Your code would need to be
public UserModels(string id, string searchcriteria)
{
// your code here
}
Then if you are wanting to return a list, add in
public List<UserData> GetUserModels(string id, string searchcriteria)
{
SSO_Methods sso = new SSO_Methods();
List<UserData> userObject = sso.GetUserObject(id, searchcriteria);
return userObject;
}
You have to create a constructor which has 2 parameters. To create a constructor you have to write something like this: [public, private, protected, internal] [classname]([parameters]).
So just change this: public List<UserData> UserModel(string id, string searchcriteria)
To public UserModel(string id, string searchcriteria). Notice that a constructor must not return anything. Use properties instead of your return type.
Related
I have a class :
public class Participant
{
[Key]
public int ParticipantId { get; set; }
[Column(TypeName ="nvarchar(50)")]
public string Email { get; set; }
[Column(TypeName = "nvarchar(50)")]
public string Name { get; set; }
public int Score { get; set; }
public int Timetaken { get; set; }
}
My endpoint:
public IActionResult GetAll()
{
var parts = _context.Participants.ToList();
if(!parts.Any())
return NotFound();
var participant = new ParticipantDto(parts);
return Ok(participant);
}
My Participant Dto:
public class ParticipantDto
{
private readonly Participant _participants;
public ParticipantDto(Participant participants)
{
_participants = participants;
}
}
I am trying the approach of passing the Participant object in the constructor and then assigning the Participant properties to DTO. I am aware how to do it for one Participant :
public string EmailAddress = _participants.Email;
etc
However, what If I want to return a List, how do I need to update my Dto to handle that?
For this statement,
var participant = new ParticipantDto(parts);
it is incorrect as you are passing the List<Participant> instance to the ParticipantDto constructor which the constructor is expected for the parameter value with the Participant type. You will get the compiler error for the unmatching type.
Hence, you need to iterate the list to transform each Participant element to the ParticipantDto type. You can use .Select() from System.Linq to do the iteration and transformation.
public IActionResult GetAll()
{
var parts = _context.Participants.ToList();
if(!parts.Any())
return NotFound();
List<ParticipantDto> participants = parts
.Select(x => new ParticipantDto(participant))
.Tolist();
return Ok(participants);
}
While in ParticipantDto, you need to perform the value mapping between the properties.
public class ParticipantDto
{
public ParticipantDto(Participant participant)
{
Email = participant.Email;
Name = participant.Name;
// Following assigning value from the properties of Participant to properties of ParticipantDto
}
public string Email { get; set; }
public string Name { get; set; }
// Following properties
}
Bonus:
You may look for AutoMapper which is a popular library for mapping between classes. (Wouldn't cover too much as the answer aims to focus and fix your current problem)
I got an error while getting json data from POST method, am I doing something wrong
C# Code:
public IActionResult signupapi(UserSignUp user)
{
var model = new Models.SignUpModelAPI(HttpContext);
if (user == null)
{
return Content(model.ResponseJsonText(false, string.Format(model.Language("empty"),
HttpContext.Request.Method, HttpContext.Request.Path.Value), Class.CodeResponse.ERROR), new Microsoft.Net.Http.Headers.MediaTypeHeaderValue("application/json"));
}
if (!model.isAllowMethod("POST"))
{
return Content(model.ResponseJsonText(false,string.Format(model.Language("notallowmethod"),
HttpContext.Request.Method,HttpContext.Request.Path.Value),Class.CodeResponse.ERROR),new Microsoft.Net.Http.Headers.MediaTypeHeaderValue("application/json"));
}
return Content(JsonConvert.SerializeObject(user));
}
public class UserSignUp
{
public string fullname { get; set; }
public string username { get; set; }
public string email { get; set; }
public string password { get; set; }
}
And this is the result when i try on reqbin every value i get is null
You need to add FromBody attribute to get your data for the POST operation:
public IActionResult signupapi([FromBody]UserSignUp user)
You can read more on parameter binding on MSDN docs.
I have a controller which is used to save data in database. The controller looks like below:
[Authorize]
[HttpPost]
public ActionResult Create(EmployeeFormViewModel viewModel)
{
var _employee = new Employee
{
Employee = User.Identity.GetUserId(),
DateTime = DateTime.Parse(string.Format("{0} {1}", viewModel.Date, viewModel.Time))
};
_context.Employees.Add(_employee);
_context.SaveChanges();
return RedirectToAction("Index", "Home");
}
I want to remove this line of code
DateTime.Parse(string.Format("{0} {1}", viewModel.Date, viewModel.Time))
and make this calculations somewhere else in order to keep the controller clean.
Which is the best way to archive this?
From the data given I see that you have used a ViewModel called EmployeeFormViewModel to saperate the logic from the model. I would guess that your ViewModel looks something like below:
public class EmployeeFormViewModel
{
public string Venue { get; set; }
public string Date { get; set; }
public string Time { get; set; }
}
Now, in order to make the changes in controller, i would suggest you make it look like below:
[Authorize]
[HttpPost]
public ActionResult Create(EmployeeFormViewModel viewModel)
{
var _employee = new Employee
{
Employee = User.Identity.GetUserId(),
DateTime = viewModel.DateTime
};
_context.Employees.Add(_employee);
_context.SaveChanges();
return RedirectToAction("Index", "Home");
}
and after that go to your ViewModel and add the new property that you added in the Controller (DateTime). Now your ViewModel should look something like below:
public class EmployeeormViewModel
{
public string Venue { get; set; }
public string Date { get; set; }
public string Time { get; set; }
public DateTime DateTime
{
get
{
return DateTime.Parse(string.Format("{0} {1}", Date, Time));
}
}
}
I hope this solves your problem.
To offer a different perspective, I'd suggest you could put it in an extension method. The concept of combining date and time strings doesn't really feel like it should belong to your domain model, it feels like a generic thing that you might want to use across your application (or even in other applications). I would do this...
public static class DateTimeExtensions
{
public static DateTime ParseToDateTime(this string date, string time = null)
{
return string.IsNullOrEmpty(withTime) ? DateTime.Parse(date) : DateTime.Parse($"{date} {time}");
}
}
And in the controller...
[Authorize]
[HttpPost]
public ActionResult Create(EmployeeFormViewModel viewModel)
{
var _employee = new Employee
{
Employee = User.Identity.GetUserId(),
DateTime = viewModel.Date.ParseToDateTime(viewModel.Time)
};
EDIT: Additionally...to incorporate etr's answer, which is also a good approach, you could combine the two...
public class EmployeeormViewModel
{
public string Venue { get; set; }
public string Date { get; set; }
public string Time { get; set; }
public DateTime DateTime
{
get
{
return Date.ParseToDateTime(Time);
}
}
}
Rich domain is the way.
public class Employee
{
public Employee(int id, object date, object time)
{
Id = id;
DateTime = DateTime.Parse(string.Format("{0} {1}", date, time))
}
public int Id { get; protected set; }
public DateTime DateTime { get; protected set; }
}
And them:
[Authorize]
[HttpPost]
public ActionResult Create(EmployeeFormViewModel viewModel)
{
_context.Employees.Add(new Employee(User.Identity.GetUserId(), viewModel.Date, viewModel.Time));
_context.SaveChanges();
return RedirectToAction("Index", "Home");
}
I like strong type binding and a Post method as follows:
public ActionResult Create(EmployeeFormViewModel viewModel)
{
viewModel.Post(User.Identity.GetUserId());
_context.Employees.Add(_employee);
_context.SaveChanges();
return RedirectToAction("Index", "Home");
}
The view model looking like this:
public class EmployeeFormViewModel
{
Employee Employee { get; set; }
DateTime Date { get; set; }
DateTime Time { get; set; }
public void Post(int empid)
{
Employee= new Employee
{
EmployeeID = empid,
DateTime = DateTime.Parse(string.Format("{0} {1}", Date, Time))
};
return;
}
}
This is all possible because of the nice MVC Binding engine which generates the EmployeeFormViewModel based on query strings, prior to calling the action method.
I put a "Post" method in all of my ViewModels and let MVC do the work.
I have this Complex Type included in my entity class, such as:
public class Logbook
{
public string CreatedBy { get; set; }
public DateTimeOffset DateCreated { get; set; }
public string ModifiedBy { get; set; }
public DateTimeOffset DateModified { get; set; }
}
Then my main class:
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public Logbook Logbook { get; set; }
}
I then set class Logbook as a complex type. My question is, I'm wondering on how to set the values in Logbook as soon as Customer entity is inserted/modified? Say, set the DateCreated to DateTime.UtcNow and set CreatedBy to a user's name.. And so on. Any help would be much appreciated. Thanks!
EDIT:
I'm using Entity Framework for my data access. And this is how I save my Customer
public ActionResult Create(Customer customer)
{
if ( Model.IsValid() )
{
_customerRepository.Insert(customer);
return View("Index");
}
return View(customer);
}
I do not konw if it possible to do it automatically. In my case I've prepared a special, generic method that handles entity update in log (it's IoC frendly in every case :) ):
public T PrepareLogbookProperty<T>(T model)
{
if (model == null)
{
throw new ArgumentNullException("model");
}
var dynamicModel = (dynamic)model;
Entity value;
try
{
value = dynamicModel.Logbook as Logbook;
}
catch (RuntimeBinderException)
{
throw new NoLogbookPropertyFound();
}
value = this.PassLog(value); // THAT METHOD PASSES CURRENT USER OR DATE TIME.
dynamicModel.Logbook= value;
return model;
}
It has one drawback - it's unfortunately dynamic. In order to handle other cases, I've preprared other overloaded function:
public TEntity PrepareLogbookProperty<TEntity>(TEntity model, Expression<Func<TEntity, Logbook>> entityExpression)
{
if (model == null)
{
throw new ArgumentNullException("model");
}
var memberExpression = (MemberExpression)entityExpression.Body;
var property = (PropertyInfo)memberExpression.Member;
var value = property.GetValue(model) as Logbook;
value = this.PassLog(value);
property.SetValue(model, value);
return model;
}
Usage:
this.helper.PrepareLogbookProperty(customer, cust => custom.MyOtherLogBook); // expression version
or
this.helper.PrepareLogbookProperty(product); // dynamic version (I assume that product has Logbook property
Method is called manually before every SaveChanges().
Unfortuantely, I couldn't change DB schema and the way that it was designed - so that solution was suitable for me.
Sample pass log:
private Logbook PassLog(Logbook entity)
{
if (entity == null)
{
entity = this.NewLogbook();
}
entity.EditedDate = this.dateTimeProvider.Now;
entity.EditorID = this.services.CurrentUser.ID;
return entity;
}
Are you after something like this?
public class Logbook
{
public Logbook(string username)
{
this.CreatedBy = username;
this.DateCreated = DateTime.UtcNow; //NB: ideally your database would provide this to ensure if deployed on multiple servers you'd have one date source
this.ModifiedBy = username;
this.DateModified = DateTime.UtcNow; //as above
}
public void Modify(string username)
{
this.ModifiedBy = username;
this.DateModified = DateTime.UtcNow; //as above
}
public string CreatedBy { get; set; }
public DateTimeOffset DateCreated { get; set; }
public string ModifiedBy { get; set; }
public DateTimeOffset DateModified { get; set; }
}
public class Customer
{
private int id;
public int Id {
get { return this.id; }
set { this.id = value; this.OnCreateOrModify(); }
}
private string name;
public string Name {
get { return this.name; }
set { this.name = value; this.OnCreateOrModify(); }
}
public Logbook Logbook { get; private set; } //presumably you don't want other classes to amend this
private void OnCreateOrModify()
{
var username = System.Environment.UserName; //or pass something into your class contructor to provide a username
if (this.Logbook == null) //create
this.Logbook = new LogBook(username);
else //modify
this.Logbook.Modify(username);
}
}
I'm trying to pass a Complex Object(Object within an object) to my action method using RedirectToAction method but it is returned null. Is there a way to do this using RouteValueDictionary?
My Model:
public class ModelUser
{
public UserLine User { get; set; }
}
public class UserLine
{
public int? UserID { get; set; }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
}
My Action method:
[HttpPost]
public async Task<ActionResult> Create(UserCreate model)
{
var valDTORegister = new RegisterLine() { Email = model.Email, Password = model.Password, OwnerType = model.OwnerType };
var result = await PostRequest<RegisterLine, UserLine>("http://localhost:10853/", "api/user/Create", valDTORegister);
var usermodel = new ModelUser();
usermodel.User = result;
return RedirectToAction("ProfileUser", new RouteValueDictionary(usermodel));
}
public ActionResult ProfileUser(ModelUser usermodel) //User object is null
{
return View();
}
I tried passing only UserLine object using RouteValueDictionary and the values has been properly passed to my ProfileUser method. This is good but I want to pass the whole ModelUser object because I may need to add more object within it.
you can connect the ProfileUser page to model ModelUser and than call this view like this:
return View("ProfileUser", usermodel);
the action shold be without parameters
public ActionResult ProfileUser()
{
return View();
}
And all data is in the model ("ModelUser") of ProfileUser