/// <summary>
        /// Allows store the new entities
        /// </summary>
        /// <param name="entitySettings">The settings of the desired CRUD</param>
        /// <param name="entityModel">The entity to save</param>
        /// <returns>True if the store process is successful; else, false</returns>
        private async Task <bool> SaveNewEntity(
            ICrudType entitySettings,
            object entityModel
            )
        {
            ModelState.Remove(entitySettings.Key.Name);
            if (!ModelState.IsValid)
            {
                return(false);
            }
            await DbContext.AddAsync(entityModel);

            try
            {
                await DbContext.SaveChangesAsync();
            }
            catch (DbUpdateException ex)
            {
                _logger.LogWarning(ex, "Failure saving changes.");
                AddSaveChangesErrorMessage();
                return(false);
            }

            return(true);
        }
        public virtual async Task <IActionResult> Create(
            ICrudType entitySettings,
            [FromBody] object entityModel
            )
        {
            var response = new JsonResponse();

            response.Success = await SaveNewEntity(entitySettings, entityModel);

            if (response.Success)
            {
                response.Data = entityModel;
            }
            else
            {
                response.Data = ModelState.Values
                                .Select(v => v.Errors.Select(e => e.ErrorMessage));
            }

            if (_requiredXml)
            {
                return(this.Xml(response, entitySettings.ModelType.Name));
            }
            else
            {
                return(Json(response));
            }
        }
        public virtual async Task <IActionResult> Create(ICrudType entitySettings)
        {
            var model = Settings as IEditModel;

            model.CurrentProcess = CrudProcesses.Create;
            return(await RenderView(nameof(Edit), model, model.SaveAction));
        }
        public virtual async Task <IActionResult> Edit(ICrudType entitySettings, string id)
        {
            await Settings.SetDataAsync(DbContext, id);

            var entity = Settings.GetData();

            return(await Edit(id, entity));
        }
        /// <summary>
        /// Initializes the attribute for a custom controller
        /// </summary>
        public CrudConstraintAttribute(Type modelType, string keyProperty = "Id")
        {
            if (string.IsNullOrWhiteSpace(keyProperty))
            {
                throw new ArgumentException(
                          $"'{nameof(keyProperty)}' cannot be null or whitespace.", nameof(keyProperty));
            }

            CrudType = Configurator.Options.Models[modelType, keyProperty];

            if (CrudType == null)
            {
                throw new ArgumentException(
                          $"Not exists a configured Crud for the model \"{modelType}\" and the key property \"{keyProperty}\"");
            }
        }
 public virtual async Task <IActionResult> Save(
     ICrudType entitySettings,
     [FromForm] object entityModel
     )
 {
     if (await SaveNewEntity(entitySettings, entityModel))
     {
         return(SendSuccessResponse(
                    entitySettings.GetKeyPropertyValue(entityModel).ToString(),
                    IndexMessages.CreateSuccess
                    ));
     }
     else
     {
         return(await Create(entitySettings));
     }
 }
        public virtual async Task <IActionResult> Index(
            ICrudType entitySettings,
            string id,
            IndexMessages message = IndexMessages.None
            )
        {
            var model = Settings as IIndexModel;

            model.SetData(DbContext);
            model.Message = new ViewMessage()
            {
                Text = message != IndexMessages.None
                    ? _localizer[$"GenericCrud.Index.{message.ToString()}Message"]
                    : string.Empty,
                CssClass = message == IndexMessages.EditSuccess ? "alert-success"
                    : message == IndexMessages.CreateSuccess ? "alert-success"
                    : message == IndexMessages.DeleteSuccess ? "alert-success"
                    : "alert-info"
            };

            if (!string.IsNullOrWhiteSpace(id))
            {
                model.SetId(id);
            }

            model.CurrentProcess = CrudProcesses.Index;

            if (_requiredJson)
            {
                return(new IndexModel(model).ToJson());
            }
            else if (_requiredXml)
            {
                return(new IndexModel(model).ToXml());
            }
            else
            {
                return(Content(
                           await _renderingService.RenderToStringAsync(nameof(Index), model, ViewData),
                           "text/html"
                           ));
            }
        }
        public virtual async Task <IActionResult> DeleteConfirm(ICrudType entitySettings, string id)
        {
            await Settings.SetDataAsync(DbContext, id);

            var entity = Settings.GetData().GetEntity();

            if (entity == null)
            {
                return(NotFound());
            }

            DbContext.Remove(entity);

            try
            {
                await DbContext.SaveChangesAsync();
            }
            catch (DbUpdateException ex)
            {
                _logger.LogWarning(ex, "Failure deleting entity.");
                var message = _localizer["GenericCrud.UnableDeleteMessage"];
                ModelState.AddModelError("",
                                         string.IsNullOrWhiteSpace(message) ?
                                         "Unable to delete the data. Try again, and if the problem persists, see your system administrator." :
                                         message
                                         );

                if (_isDeleteRequest)
                {
                    return(StatusCode(500, "Failure deleting entity."));
                }
            }

            if (_isDeleteRequest)
            {
                return(Ok());
            }
            else
            {
                return(SendSuccessResponse(id, IndexMessages.DeleteSuccess));
            }
        }
        public IActionResult GetScript(ICrudType entitySettings, string fileName)
        {
            var assembly = typeof(GenericController).GetTypeInfo().Assembly;

            // This shows the available items.
            string[] resources = assembly.GetManifestResourceNames();

            var namespase = typeof(Configurator).Namespace;
            var stream    = assembly.GetManifestResourceStream($"{namespase}.js.{fileName}.js");

            if (stream == null)
            {
                return(NotFound());
            }

            using (var reader = new StreamReader(stream))
            {
                var bytes = Encoding.UTF8.GetBytes(reader.ReadToEnd());
                return(File(bytes, "application/javascript"));
            }
        }
        /// <summary>
        /// Tries initializes the <see cref="Settings"/> property
        /// </summary>
        /// <param name="context">The action executing context.</param>
        protected void InitSettings(ActionExecutingContext context)
        {
            if (Settings == null)
            {
                if (!context.ActionArguments.TryGetValue(Constants.EntitySettingsRouteKey, out object entityName) &&
                    !context.RouteData.Values.TryGetValue(Constants.EntitySettingsRouteKey, out entityName))
                {
                    throw new InvalidOperationException($"Entity name not found.");
                }

                CrudType = entityName is ICrudType
                    ? entityName as ICrudType
                    : Configurator.Options.Models[entityName.ToString()];
                if (CrudType == null)
                {
                    throw new InvalidOperationException($"Configured model not found for {entityName}");
                }

                var type        = typeof(CrudModel <,>).MakeGenericType(CrudType.ModelType, CrudType.Key.Type);
                var constructor = type.GetConstructor(
                    bindingAttr: BindingFlags.Instance | BindingFlags.NonPublic,
                    binder: null,
                    types: new Type[]
                {
                    typeof(ICrudType),
                    typeof(IStringLocalizer),
                    typeof(IUrlHelper),
                    typeof(ILoggerFactory)
                },
                    modifiers: null
                    );

                Settings = constructor?.Invoke(new object[] { CrudType, _localizer, Url, _loggerFactory }) as IViewModel
                           ?? null;
            }
        }
        /// <summary>
        /// Allows valid and save the changes into the specified entity
        /// </summary>
        /// <param name="entitySettings">The settings of the desired CRUD</param>
        /// <param name="id">The id of the entity to change</param>
        /// <param name="entityModel">Instance with the changes of the entity to save</param>
        /// <param name="supportApiResponse">True to respond to Api Rest requests; False for ignoring them</param>
        private async Task <IActionResult> SaveEntityChangesAsync(
            ICrudType entitySettings,
            string id,
            object entityModel,
            bool supportApiResponse = false
            )
        {
            Settings.SetId(id);
            var key = Settings.GetId();

            var model = Settings as IEditModel;

            model.SetData(entityModel);

            var modelId = model.GetId();

            if (!entitySettings.Key.IsEditable && !modelId.Equals(key))
            {
                return(NotFound());
            }

            if (ModelState.IsValid)
            {
                await Settings.SetDataAsync(DbContext, id);

                var entity = Settings.GetData().GetEntity();

                if (entity == null)
                {
                    return(NotFound());
                }

                if (!entitySettings.Key.IsEditable || modelId.Equals(key))
                {
                    DbContext.Entry(entity).CurrentValues.SetValues(entityModel);
                }
                else
                {
                    DbContext.Remove(entity);
                    await DbContext.AddAsync(entityModel);
                }

                try
                {
                    await DbContext.SaveChangesAsync();
                }
                catch (DbUpdateException ex)
                {
                    _logger.LogWarning(ex, "Failure saving changes.");
                    AddSaveChangesErrorMessage();
                }

                if (supportApiResponse)
                {
                    var response = new JsonResponse()
                    {
                        Success = true,
                        Data    = Settings.GetData().GetEntity()
                    };

                    if (_requiredXml)
                    {
                        return(this.Xml(response, entitySettings.ModelType.Name));
                    }
                    else
                    {
                        return(Json(response));
                    }
                }
                else
                {
                    return(SendSuccessResponse(modelId.ToString(), IndexMessages.EditSuccess));
                }
            }

            if (supportApiResponse)
            {
                var response = new JsonResponse()
                {
                    Success = false,
                    Data    = ModelState.Values
                              .Select(v => v.Errors.Select(e => e.ErrorMessage))
                };

                if (_requiredXml)
                {
                    return(this.Xml(response, entitySettings.ModelType.Name));
                }
                else
                {
                    return(Json(response));
                }
            }
            else
            {
                return(await Edit(id, Settings.GetData()));
            }
        }
 public virtual Task <IActionResult> SaveChangesAsync(
     ICrudType entitySettings,
     string id,
     [FromForm] object entityModel
     ) => SaveEntityChangesAsync(entitySettings, id, entityModel, supportApiResponse: false);
 public virtual Task <IActionResult> Edit(
     ICrudType entitySettings,
     string id,
     [FromBody] object entityModel
     ) => SaveEntityChangesAsync(entitySettings, id, entityModel, supportApiResponse: true);
 public virtual Task <IActionResult> Delete(ICrudType entitySettings, string id)
 => ShowDetailsAsync(id, isForDeletion: true);
 public virtual Task <IActionResult> Details(ICrudType entitySettings, string id)
 => ShowDetailsAsync(id, supportApiResponse: true);