System.MissingMethodException: для этого объекта не определен конструктор без параметров - PullRequest
0 голосов
/ 04 октября 2011

Я периодически получаю эту ошибку в своем веб-приложении MVC 2. Мои модели не имеют конструкторов без параметров, они выглядят так:

    public AddParentModel(ITracktionDataLayer dataLayer, MessagePasser messager, AuthUserHelper authUser)
    {
        _model = new PersonAddEditModel(messager, dataLayer, authUser, null);
    }

Я должен отметить, что мои контроллеры имеют конструкторы без параметров. PersonAddEditModel не предоставляется напрямую MVC. AddParentModel существует только для упрощения привязки MVC.

Поскольку AddParentModel (и все другие модели, которые использует MVC) существует на сервере, я мог бы сделать их без параметров, хотя это немного испортило бы мои методы тестирования. Странная часть этого заключается в том, что это происходит с перебоями. Я ожидаю, что подобная проблема будет происходить постоянно, но это определенно не так - я просто получаю, что ELMAH отправляет мне электронное письмо через день или около того с каким-то несчастным пользователь получает эту ошибку.

Я хотел бы знать, какие у меня есть варианты. Самым простым способом решения этой проблемы, который я вижу, является создание перегрузки конструктора, которая просто устанавливает эти параметры для объектов по умолчанию (что я, вероятно, сделаю просто для того, чтобы исправить проблему на данный момент, но я чувствую себя настолько грязно, делая это), но я хотел бы получить мнение людей о правильном способе справиться с этим. Я относительно новичок в MVC. Заранее спасибо!

РЕДАКТИРОВАТЬ: Я хотел бы добавить, что в моих методах [HttpPost], где выполняется обработка, хотя я использую модель для редактирования MVC в представлении, я получаю обратно FormCollection и использую чтобы обновить модель, вместо того, чтобы MVC редактировал модель напрямую.

    /// <summary>
    /// Add this person, then go to the next page where more people can be added.
    /// </summary>
    /// <param name="model"></param>
    /// <returns></returns>
    [HttpPost]
    public ActionResult Index(FormCollection fc, HttpPostedFileWrapper upload) {

        Uri requestUri = !Request.Url.ToString().Contains("/127.0.0.1/") ? Request.Url : new Uri("...");
        MessagePasser messager = new MessagePasser();
        ITracktionDataLayer dataLayer = DataFactory.GetDataLayer();
        AuthUserHelper user = AuthUserHelper.AnonymousWebUserFrom(dataLayer, requestUri);
        AddParentModel model = new AddParentModel(dataLayer, messager, user);

        if (TryUpdateModel(model, fc) && ModelState.IsValid)
        {
        ...

Я также понимаю, что для некоторых моделей я не могу создать конструктор без параметров, потому что для некоторых моделей требуется пара дополнительных примитивов выше моего уровня данных, уровня обмена сообщениями и аутентифицированного пользователя.

1 Ответ

1 голос
/ 05 октября 2011

Я не могу использовать внедрение зависимостей для решения этой проблемы, потому что я запрашиваю дополнительные параметры, которые зависят от информации пользователя в конструкторе. Мой конструктор использует IDataLayer, MessagePasser и AuthUserHelper, которые являются общими для всех моделей, но я также запрашиваю два идентификатора int, которые зависят от некоторых скрытых полей ввода или параметров строки запроса.

Поэтому я собираюсь разделить свойства модели на ее собственный класс (модель) и фактическую обработку, такую ​​как загрузка и сохранение в классе обслуживания. Модель представляет собой просто пакет свойств и может иметь конструктор без параметров, в то время как класс обслуживания будет вызываться для заполнения и сохранения данных. Я надеюсь, что этот ответ кому-то поможет.

Итак, прежде чем я имел:

public class EditFamilyMemberModel
{


    #region Constructor

    public EditFamilyMemberModel(ITracktionDataLayer dataLayer, MessagePasser messager, AuthUserHelper authUser, int originalPersonID, int familyMemberID)
    {
        _dataLayer = dataLayer;
        _originalPerson = new PersonAddEditModel(messager, dataLayer, authUser, originalPersonID);
        _model = new PersonAddEditModel(messager, dataLayer, authUser, familyMemberID);
        _grades = _dataLayer.GetGradesForOrganization(authUser.OrganizationID, _model.Person.Grade, true).ToArray();
    }

    #endregion

    #region Private

    ITracktionDataLayer _dataLayer;
    PersonAddEditModel _originalPerson;
    PersonAddEditModel _model;
    IList<Grade> _grades;

    #endregion

    #region Properties

    #region Read Only

    public Person Person
    {
        get { return _model.Person; }
    }

    public AuthUserHelper AuthUser
    {
        get { return _model.AuthUser; }
    }

    public IList<School> Schools
    {
        get { return _model.Schools; }
    }

    public IList<ContactType> ContactTypes
    {
        get { return _model.ContactTypes; }
    }

    public IList<string> Genders
    {
        get { return _model.Genders; }
    }

    public IList<Grade> Grades
    {
        get { return /*_model.Grades;*/ _grades; }
    }

    public IList<USState> USStates
    {
        get { return _model.USStates; }
    }

    public IList<PersonType> PersonTypes
    {
        get { return _model.PersonTypes; }
    }

    public IList<FamilyRole> FamilyRoles
    {
        get { return _model.FamilyRoles; }
    }

    #endregion

    [Required]
    [StringLength(100)]
    public string Address
    {
        get { return _model.Person.Address; }
        set { _model.Person.Address = value; }
    }


    [StringLength(100)]
    public string Address2
    {
        get { return _model.Person.Address2; }
        set { _model.Person.Address2 = value; }
    }

    [Required]
    [StringLength(50)]
    public string City
    {
        get { return _model.Person.City; }
        set { _model.Person.City = value; }
    }

    [Required]
    [StringLength(50)]
    public string State
    {
        get { return _model.Person.State; }
        set { _model.Person.State = value; }
    }

    [Required]
    [StringLength(50)]
    public string Zip
    {
        get { return _model.Person.Zip; }
        set { _model.Person.Zip = value; }
    }

    [DataType(DataType.Date)]
    //[Required]
    public DateTime? DOB
    {
        get { return _model.Person.DOB; }
        set { _model.Person.DOB = value; }
    }

    [Required]
    public string Gender
    {
        get { return _model.Person.Gender; }
        set { _model.Person.Gender = value; }
    }

    [Required]
    public string FirstName
    {
        get { return _model.Person.FirstName; }
        set { _model.Person.FirstName = value; }
    }

    [Required]
    public string LastName
    {
        get { return _model.Person.LastName; }
        set { _model.Person.LastName = value; }
    }

    public int? SchoolID
    {
        get { return _model.Person.SchoolID; }
        set { _model.Person.SchoolID = value; }
    }

    public int? GradeID
    {
        get { return _model.Person.Grade; }
        set { _model.Person.Grade = value; }
    }

    public string SpecialNeedsDescription
    {
        get { return _model.Person.SpecialNeedsDescription; }
        set { _model.Person.SpecialNeedsDescription = value; }
    }

    public string SpecialNeedsSummary
    {
        get { return _model.Person.SpecialNeedsSummary; }
        set { _model.Person.SpecialNeedsSummary = value; }
    }

    public byte[] PictureData
    {
        get;
        set;
    }

    public string PictureAction
    {
        get;
        set;
    }


    #region Membership

    [Display(Name = "User Name")]
    [DisplayName("User Name")]
    [UniqueUserName(ErrorMessage = "The user name specified is already in use, please choose another user name.")]
    public string Username { get; set; }

    [Display(Name = "Password")]
    [DisplayName("Enter a password")]
    [StringLength(50, MinimumLength = 6, ErrorMessage = "Password must be at least 6 characters long.")]
    public string Password { get; set; }

    [DisplayName("Confirm Password")]
    [StringLength(50, MinimumLength = 6)]
    public string PasswordConfirm { get; set; }

    #endregion

    #region Abstracted Contact Methods

    /// <summary>
    /// When adding someone, this represents the phone number contact record.
    /// </summary>
    [Display(Name = "Home Phone Number")]
    [DisplayName("Home Phone Number")]
    [USPhoneNumber]
    //[Required]
    public string HomePhoneNumber
    {
        get { return _model.HomePhone; }
        set { _model.HomePhone = value; }
    }

    /// <summary>
    /// When adding someone, this represents the phone number contact record.
    /// </summary>
    [Display(Name = "Cell Phone Number")]
    [DisplayName("Cell Phone Number")]
    [USPhoneNumber]
    //[Required]
    public string CellPhoneNumber
    {
        get { return _model.PersonalCell; }
        set { _model.PersonalCell = value; }
    }

    /// <summary>
    /// When adding someone, this represents the email address contact record.
    /// </summary>
    [Display(Name = "Email Address")]
    [DisplayName("Email Address")]
    //[Required] -- Some parents dont have email addresses
    [UniqueEmailAddress(ErrorMessage = "The email address was already found in our system, please sign in or use another email.")]
    [Email(ErrorMessage = "The email address specified isn't an email address.")]
    public string EmailAddress
    {
        get { return _model.EmailAddress; }
        set { _model.EmailAddress = value; }
    }

    #endregion

    #endregion

    #region Logic

    public void SaveChanges()
    {
        _model.Person.ChangedTimeStamp = DateTime.Now;
        _model.Person.ChangedBy = -1;

        // If we have a valid home #, add it
        if (!string.IsNullOrWhiteSpace(HomePhoneNumber))
            _model.HomePhone = HomePhoneNumber;

        // If we have a valid cell #, add it
        if (!string.IsNullOrWhiteSpace(CellPhoneNumber))
            _model.PersonalCell = CellPhoneNumber;

        // If we have a valid email, add it
        if (!string.IsNullOrWhiteSpace(EmailAddress))
            _model.EmailAddress = EmailAddress;

        // Some fields may have 'not applicable'; blank them
        _model.Person.SpecialNeedsDescription = _model.Person.SpecialNeedsDescription.NormalizeNotApplicable().NullIfEmptyOrWhitespace();
        _model.Person.SpecialNeedsSummary = _model.Person.SpecialNeedsSummary.NormalizeNotApplicable().NullIfEmptyOrWhitespace();

        // Names of people should be proper case if they're all entered in lowercase
        _model.Person.FirstName = _model.Person.FirstName.NormalizeName();
        _model.Person.LastName = _model.Person.LastName.NormalizeName();

        if (PictureData != null && (PictureAction == "replace" || (PictureAction ?? "") == ""))
        {
            // Replace just adds, it does not remove the old picture.
            Photo pic = PhotoHandling.GetPhotoEntityFromBytes(PictureData);
            pic.ROWGUID = Guid.NewGuid();
            pic.OrganizationID = _model.AuthUser.OrganizationID;
            pic.CreationTimestamp = DateTime.Now;
            pic.Deleted = false;
            _model.AddNewPhoto(pic);
            _model.Person.Avatar = pic.ROWGUID;
        }
        else if (PictureAction == "remove" && _model.Person.Avatar.HasValue)
        {
            var pic = _model.Person.Photos.SingleOrDefault(p => p.ROWGUID == _model.Person.Avatar.Value);
            if (pic != null)
            {
                pic.Deleted = true;
                _model.Person.Avatar = null;
            }
        }

        _model.SaveChanges();

    }

    #endregion

}

Теперь я разделил его на:

public class EditFamilyMemberModel
{

    public EditFamilyMemberModel() { }

    #region Properties

    [Required]
    [StringLength(100)]
    public string Address { get; set; }

    [StringLength(100)]
    public string Address2 { get; set; }

    [Required]
    [StringLength(50)]
    public string City { get; set; }

    [Required]
    [StringLength(50)]
    public string State { get; set; }

    [Required]
    [StringLength(50)]
    public string Zip { get; set; }

    [DataType(DataType.Date)]
    //[Required]
    public DateTime? DOB { get; set; }

    [Required]
    public string Gender { get; set; }

    [Required]
    public string FirstName { get; set; }

    [Required]
    public string LastName { get; set; }

    public int? SchoolID { get; set; }

    public int? GradeID { get; set; }

    public string SpecialNeedsDescription { get; set; }

    public string SpecialNeedsSummary { get; set; }

    public byte[] PictureData { get; set; }

    public string PictureAction { get; set; }

    #region Membership

    [Display(Name = "User Name")]
    [DisplayName("User Name")]
    [UniqueUserName(ErrorMessage = "The user name specified is already in use, please choose another user name.")]
    public string Username { get; set; }

    [Display(Name = "Password")]
    [DisplayName("Enter a password")]
    [StringLength(50, MinimumLength = 6, ErrorMessage = "Password must be at least 6 characters long.")]
    public string Password { get; set; }

    [DisplayName("Confirm Password")]
    [StringLength(50, MinimumLength = 6)]
    public string PasswordConfirm { get; set; }

    #endregion

    #region Abstracted Contact Methods

    /// <summary>
    /// When adding someone, this represents the phone number contact record.
    /// </summary>
    [Display(Name = "Home Phone Number")]
    [DisplayName("Home Phone Number")]
    [USPhoneNumber]
    //[Required]
    public string HomePhoneNumber { get; set; }

    /// <summary>
    /// When adding someone, this represents the phone number contact record.
    /// </summary>
    [Display(Name = "Cell Phone Number")]
    [DisplayName("Cell Phone Number")]
    [USPhoneNumber]
    //[Required]
    public string CellPhoneNumber { get; set; }

    /// <summary>
    /// When adding someone, this represents the email address contact record.
    /// </summary>
    [Display(Name = "Email Address")]
    [DisplayName("Email Address")]
    //[Required] -- Some parents dont have email addresses
    //[UniqueEmailAddress(ErrorMessage = "The email address was already found in our system, please sign in or use another email.")]
    [Email(ErrorMessage = "The email address specified isn't an email address.")]
    public string EmailAddress { get; set; }

    #endregion

    #endregion

    #region Read-Only Properties

    public IList<School> Schools { get; internal set; }

    public IList<ContactType> ContactTypes { get; internal set; }

    public IList<string> Genders { get; internal set; }

    public IList<Grade> Grades { get; internal set; }

    public IList<USState> USStates { get; internal set; }

    public IList<PersonType> PersonTypes { get; internal set; }

    public IList<FamilyRole> FamilyRoles { get; internal set; }

    public Person Person { get; internal set; }

    #endregion

}

public class EditFamilyMemberService
{

    #region Constructor

    public EditFamilyMemberService(ITracktionDataLayer dataLayer, MessagePasser messager, AuthUserHelper authUser, int originalPersonID, int familyMemberID)
    {
        _dataLayer = dataLayer;
        _originalPerson = new PersonAddEditModel(messager, dataLayer, authUser, originalPersonID);
        _model = new PersonAddEditModel(messager, dataLayer, authUser, familyMemberID);
        _grades = _dataLayer.GetGradesForOrganization(authUser.OrganizationID, _model.Person.Grade, true).ToArray();
        Model = new EditFamilyMemberModel()
        {
            Address = _model.Person.Address,
            Address2 = _model.Person.Address2,
            CellPhoneNumber = _model.PersonalCell,
            City = _model.Person.City,
            ContactTypes = _model.ContactTypes,
            DOB = _model.Person.DOB,
            EmailAddress = _model.EmailAddress,
            FamilyRoles = _model.FamilyRoles,
            FirstName = _model.Person.FirstName,
            Gender = _model.Person.Gender,
            Genders = _model.Genders,
            GradeID = _model.Person.Grade,
            Grades = _model.Grades,
            HomePhoneNumber = _model.HomePhone,
            LastName = _model.Person.LastName,
            Password = null,
            PasswordConfirm = null,
            PersonTypes = _model.PersonTypes,
            PictureAction = null,
            PictureData = null,
            SchoolID = _model.Person.SchoolID,
            Schools = _model.Schools,
            SpecialNeedsDescription = _model.Person.SpecialNeedsDescription,
            SpecialNeedsSummary = _model.Person.SpecialNeedsSummary,
            State = _model.Person.State,
            Username = null,
            USStates = _model.USStates,
            Zip = _model.Person.Zip,
            Person = _model.Person
        };
    }

    #endregion

    #region Private

    ITracktionDataLayer _dataLayer;
    PersonAddEditModel _originalPerson;
    PersonAddEditModel _model;
    IList<Grade> _grades;

    #endregion

    #region Properties

    public EditFamilyMemberModel Model { get; internal set; }

    #region Read Only

    public Person Person
    {
        get { return _model.Person; }
    }

    public AuthUserHelper AuthUser
    {
        get { return _model.AuthUser; }
    }

    #endregion


    #endregion

    #region Logic

    public void SaveChanges()
    {
        _model.Person.ChangedTimeStamp = DateTime.Now;
        _model.Person.ChangedBy = -1;

        // If we have a valid home #, add it
        if (!string.IsNullOrWhiteSpace(Model.HomePhoneNumber))
            _model.HomePhone = Model.HomePhoneNumber;

        // If we have a valid cell #, add it
        if (!string.IsNullOrWhiteSpace(Model.CellPhoneNumber))
            _model.PersonalCell = Model.CellPhoneNumber;

        // If we have a valid email, add it
        if (!string.IsNullOrWhiteSpace(Model.EmailAddress))
            _model.EmailAddress = Model.EmailAddress;

        // Some fields may have 'not applicable'; blank them
        Model.SpecialNeedsDescription = Model.SpecialNeedsDescription.NormalizeNotApplicable().NullIfEmptyOrWhitespace();
        Model.SpecialNeedsSummary = Model.SpecialNeedsSummary.NormalizeNotApplicable().NullIfEmptyOrWhitespace();

        // Names of people should be proper case if they're all entered in lowercase
        Model.FirstName = Model.FirstName.NormalizeName();
        Model.LastName = Model.LastName.NormalizeName();

        // Save this extra information
        _model.Person.Address = Model.Address;
        _model.Person.Address2 = Model.Address2;
        _model.PersonalCell = Model.CellPhoneNumber;
        _model.Person.City = Model.City;
        _model.Person.DOB = Model.DOB;
        _model.EmailAddress = Model.EmailAddress;
        _model.Person.FirstName = Model.FirstName;
        _model.Person.Gender = Model.Gender;
        _model.Person.Grade = Model.GradeID;
        _model.HomePhone = Model.HomePhoneNumber;
        _model.Person.LastName = Model.LastName;
        _model.Person.SchoolID = Model.SchoolID;
        _model.Person.SpecialNeedsDescription = Model.SpecialNeedsDescription;
        _model.Person.SpecialNeedsSummary = Model.SpecialNeedsSummary;
        _model.Person.State = Model.State;
        _model.Person.Zip = Model.Zip;

        // Save picture data
        if (Model.PictureData != null && (Model.PictureAction == "replace" || (Model.PictureAction ?? "") == ""))
        {
            // Replace just adds, it does not remove the old picture.
            Photo pic = PhotoHandling.GetPhotoEntityFromBytes(Model.PictureData);
            pic.ROWGUID = Guid.NewGuid();
            pic.OrganizationID = _model.AuthUser.OrganizationID;
            pic.CreationTimestamp = DateTime.Now;
            pic.Deleted = false;
            _model.AddNewPhoto(pic);
            _model.Person.Avatar = pic.ROWGUID;
        }
        else if (Model.PictureAction == "remove" && _model.Person.Avatar.HasValue)
        {
            var pic = _model.Person.Photos.SingleOrDefault(p => p.ROWGUID == _model.Person.Avatar.Value);
            if (pic != null)
            {
                pic.Deleted = true;
                _model.Person.Avatar = null;
            }
        }

        _model.SaveChanges();

    }

    #endregion

}

Сама модель не требует каких-либо параметров ctor и больше не должна выдавать эту ошибку. Я большой поклонник инкапсуляции связанной логики и данных в одном классе, но, поскольку это всего лишь оболочка для тяжелой PersonAddEditModel, и она используется только на стороне MVC, я могу с этим справиться.

Если у кого-то есть какие-либо замечания или альтернативы тому, что я только что опубликовал, я весь в ушах.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...