|
That was fast. Thank you!
Yeah, I figured out that is the other way around, I forgot module when writing my call for scaffolder.
It was
Scafold Module Product Products
So my question is: lets say I follow your approach and start implementing after scaffolding finishes.
What would be the steps in your opinion:
1. Add Properties with Validation and DB Attributes to the POCO
2. Create the privileges in Configuration.cs
3. Add migration and update the new Entities to the database
4. Create View classes
5. Implement Validation classes
6. Update sitemap and routing stuff
7. Update the cshtml views (was there a scaffolding for that?)
Am I missing something?
Never the less I am curious how the approach the other way around will go for you.
best regards!
|
|
|
|
|
Generally it's:
1) Add map call in ObjectMapper.cs
2) Add properties to model and view.
3) Add migrations to data and test projects.
4) Add privileges to Configuration.cs.
5) Add resources in Privileges - Action, Controller, Area (optional).
6) Add resources for ContentTitles and Headers.
7) Add resource to SiteMap.
8) Add resources for all views in Views folder.
9) Register your service and validator in MainContainer.cs.
10) Add sitemap to Mvc.sitemap
11) Make your UI in razor views.
12) Add privileges to initial data tests.
13) Add your service and validator tests in MainContainerTests.cs
Everything else is optional I believe. It may seem a lot but must of the time it's just translating resources. I'm making a working "module" with basic validations in like 30 minutes (practice makes perfect ).
modified 25-Mar-21 21:01pm.
|
|
|
|
|
Nr 1. has been scaffolded
private static void MapProducts()
{
Mapper.CreateMap<Product, ProductView>();
Mapper.CreateMap<ProductView, Product>();
}
|
|
|
|
|
Yes it's scaffolded but it's not "called"
modified 25-Mar-21 21:01pm.
|
|
|
|
|
|
Did you have time yet to look at the "other way around" scaffolding?
|
|
|
|
|
Yes I did, and it's not that easy to do, so it may take some time
And I'm still wondering about approach to this too, should I create new "module xxx" or leave the current one with "existing model check" ~~
modified 25-Mar-21 21:01pm.
|
|
|
|
|
How do I add migrations and update the test project Database?, I’ve executed the Add-Migration and Update-Database command in the Test project, the database was created and added the Migration too , of course the database is empty, but even after succeeded Migration, I’m still having 227 test failing because of Backing Model changed.
“The model backing the 'TestingContext' context has changed since the database was created. Consider using Code First Migrations to update the database”
Can you help me please, I will be happy to have all my test passed.
Second question.
There is more than tree failing test caused by bad date format of data picker, I supposed that the actual value will be retrieved from the translated string in script folder, but it look like it is being retrieved from the system date time format.
Help please, than you very much.
Expected: <input autocomplete="off" class="form-control datepicker" id="Relation_Date" name="Relation.Date" type="text" value="2011.01.01" />
Actual: <input autocomplete="off" class="form-control datepicker" id="Relation_Date" name="Relation.Date" type="text" value="2011-01-01" />
$.datepicker.regional['lt-LT'] = {
closeText: 'Uždaryti',
prevText: '<Atgal',
nextText: 'Pirmyn>',
currentText: 'Šiandien',
monthNames: ['Sausis', 'Vasaris', 'Kovas', 'Balandis', 'Gegužė', 'Birželis', 'Liepa', 'Rugpjūtis', 'Rugsėjis', 'Spalis', 'Lapkritis', 'Gruodis'],
monthNamesShort: ['Sau', 'Vas', 'Kov', 'Bal', 'Geg', 'Bir', 'Lie', 'Rugp', 'Rugs', 'Spa', 'Lap', 'Gru'],
dayNames: ['sekmadienis', 'pirmadienis', 'antradienis', 'trečiadienis', 'ketvirtadienis', 'penktadienis', 'šeštadienis'],
dayNamesShort: ['sek', 'pir', 'ant', 'tre', 'ket', 'pen', 'šeš'],
dayNamesMin: ['Se', 'Pr', 'An', 'Tr', 'Ke', 'Pe', 'Še'],
weekHeader: 'Sav',
dateFormat: 'yy.mm.dd',
firstDay: 1,
isRTL: false,
showMonthAfterYear: false,
yearSuffix: ''
};
$.timepicker.regional['lt-LT'] = {
timeOnlyTitle: 'Pasirinkite laiką',
timeText: 'Laikas',
hourText: 'Valandos',
minuteText: 'Minutės',
secondText: 'Sekundės',
millisecText: 'Milisekundės',
microsecText: 'Mikrosekundės',
timezoneText: 'Laiko zona',
currentText: 'Dabar',
closeText: 'Uždaryti',
timeFormat: 'HH:mm',
amNames: ['priešpiet', 'AM', 'A'],
pmNames: ['popiet', 'PM', 'P'],
isRTL: false
};
$.datepicker.setDefaults($.datepicker.regional['lt-LT']);
$.timepicker.setDefaults($.timepicker.regional['lt-LT']);
/***********************************************************************
AM: null,
PM: null,
patterns: {
d: "yyyy.MM.dd",
dt: "yyyy.MM.dd HH:mm",
D: "yyyy 'm.' MMMM d 'd.'",
t: "HH:mm",
T: "HH:mm:ss",
f: "yyyy 'm.' MMMM d 'd.' HH:mm",
F: "yyyy 'm.' MMMM d 'd.' HH:mm:ss",
M: "MMMM d 'd.'",
Y: "yyyy 'm.' MMMM"
}
}
}
});
}( this ));
Globalize.culture("lt-LT");
AF Matambo
|
|
|
|
|
1) Just try deleting database file and it's connection in SQL explorer and rerun update-database on both Data and Test projects. Because there are a lot of stuff which can brake migrations.
2) Could you provide failing test names? I'm 99% sure that it's machine culture related.
modified 25-Mar-21 21:01pm.
|
|
|
|
|
Ok I'll do it but need time to collect all test names.
AF Matambo
|
|
|
|
|
I’m having problems when I add more languages in the globalization, when it starts the foreach loop after selecting the third element it is being returned null string in abbreviation attribute. The error is occurring in the GlobalizationProvider method when adding elements to the LanguageDictionary.
According to your reply on this issue in my previous question, I have everything in place, but I had a problem this time in updated application to 1.3.0 version of the template, if I comment all the additional languages, the application runs smoothly with the 2 languages.
Where did I am doing something wrong?
Thank you in advance.
="1.0"="utf-8"
<globalization>
<language name="English" culture="en-GB" abbreviation="en" default="true" />
<language name="Lietuvių" culture="lt-LT" abbreviation="lt" />
<language name="Español" culture="es-ES" abbrevation="es" />
<language name="Português" culture="pt-PT" abbrevation="pt" />
<language name="Français" culture="fr-FR" abbrevation="fr" />
<language name="Italiano" culture="it-IT" abbrevation="it" />
<language name="Deutsch" culture="de-DE" abbrevation="de" />
</globalization>
public void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes
.MapRoute(
"DefaultMultilingual",
"{language}/{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new { language = "es|pt|fr|it|de|lt" },
new[] { "VumbaSoft.AdventureWorks.Controllers" })
.DataTokens["UseNamespaceFallback"] = false;
routes
.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { language = "en", controller = "Home", action = "Index", id = UrlParameter.Optional },
new { language = "en" },
new[] { "VumbaSoft.AdventureWorks.Controllers" })
.DataTokens["UseNamespaceFallback"] = false;
}
public override void RegisterArea(AreaRegistrationContext context)
{
context
.MapRoute(
"AdministrationMultilingual",
"{language}/Administration/{controller}/{action}/{id}",
new { area = "Administration", action = "Index", id = UrlParameter.Optional },
new { language = "es|pt|fr|it|de|lt" },
new[] { "VumbaSoft.AdventureWorks.Controllers.Administration" });
context
.MapRoute(
"Administration",
"Administration/{controller}/{action}/{id}",
new { language = "en", area = "Administration", action = "Index", id = UrlParameter.Optional },
new { language = "en" },
new[] { "VumbaSoft.AdventureWorks.Controllers.Administration" });
}
}
public GlobalizationProvider(String path)
{
XElement languagesXml = XElement.Load(path);
LanguageDictionary = new Dictionary<String, Language>();
foreach (XElement languageNode in languagesXml.Elements("language"))
{
Language language = new Language();
language.Culture = new CultureInfo((String)languageNode.Attribute("culture"));
language.IsDefault = (Boolean?)languageNode.Attribute("default") == true;
language.Abbreviation = (String)languageNode.Attribute("abbreviation");
language.Name = (String)languageNode.Attribute("name");
LanguageDictionary.Add(language.Abbreviation, language);
}
Languages = LanguageDictionary.Select(language => language.Value).ToArray();
DefaultLanguage = Languages.Single(language => language.IsDefault);
}
AF Matambo
|
|
|
|
|
Its "abbreviation" not "abbrevation"
modified 25-Mar-21 21:01pm.
|
|
|
|
|
oh yes, this was a problem, I made the correction and now all work very well. many thanks.
AF Matambo
|
|
|
|
|
1- Is this a way of programming in T4 language for generating the Delete and Edit validation for all newly generated Validators? Do I need to correct somewhere in this assembly or Test project?
2- How can I create the respective resources: Validations.EditOrDeleteAllowedToCreatorUser, Validations.EditOrDeleteNotAllowed, Validations.EditIsNotAllowed and Validations.DeleteIsNotAllowed
namespace Vumbasoft.AdventureWorks.Validators
{
public interface <#= Model.IValidator #> : IValidator
{
Boolean CanCreate(<#= Model.View #> view);
Boolean CanDelete(<#= Model.View #> view);
Boolean CanEdit(<#= Model.View #> view);
}
}
********************************************************************************
namespace Vumbasoft.AdventureWorks.Validators
{
public class <#= Model.Validator #> : BaseValidator, <#= Model.IValidator #>
{
public <#= Model.Validator #>(IUnitOfWork unitOfWork)
: base(unitOfWork)
{
}
public Boolean CanCreate(<#= Model.View #> view)
{
boolean isValid = ModelState.IsValid;
return isValid;
}
public Boolean CanDelete(<#= Model.View #> view)
{
boolean isValid = ModelState.IsValid;
isValid &= IsAllowedAction(view, "CanDelete");
return isValid;
}
public Boolean CanEdit(<#= Model.View #> view)
{
boolean isValid = ModelState.IsValid;
isValid &= IsAllowedAction(view, "CanEdit");
return isValid;
}
private Boolean IsAllowedAction(<#= Model.View #> view, string caller)
{
if (view.CreatedBy != HttpContext.Current.User.Identity.Name)
{
ModelState.AddModelError<<#= Model.View #>>(mod => mod.Name, Validations.EditOrDeleteAllowedToCreatorUser);
return false;
}
if (DateTime.Now.Subtract(view.CreationDate).TotalDays > 1)
{
ModelState.AddModelError<<#= Model.View #>>(mod => mod.Name, Validations.EditOrDeleteNotAllowed);
return false;
}
if (DateTime.Now.Subtract(view.CreationDate).TotalHours > 2 && caller == "CanEdit")
{
ModelState.AddModelError<<#= Model.View #>>(mod => mod.Name, Validations.EditIsNotAllowed);
return false;
}
if (DateTime.Now.Subtract(view.CreationDate).TotalHours > 1&& caller == "CanDelete")
{
ModelState.AddModelError<<#= Model.View #>>(mod => mod.Name, Validations.DeleteIsNotAllowed);
return false;
}
return true;
}
}
}
AF Matambo
|
|
|
|
|
1) Yes you would only need to update Validator.cs.t4 and ValidatorTests.cs.t4 file if you want to generate different validators.
2) Resources have to be created by hand in the Resources project.
modified 25-Mar-21 21:01pm.
|
|
|
|
|
Thank you so much, for your replay.
AF Matambo
|
|
|
|
|
1- I need to validate a Delete Action using a function as shown below, how can I implement it in already generated code in UnitOfWork Class methods for Delete Action, can it be automated for the next scaffolding process via T4 Templates?
2- where did I need to touch in Test project to continue passing all test?
public class RoleValidator : BaseValidator, IRoleValidator
{
public RoleValidator(IUnitOfWork unitOfWork)
: base(unitOfWork)
{
}
public Boolean CanCreate(RoleView view)
{
Boolean isValid = ModelState.IsValid;
isValid &= IsUniqueRole(view);
return isValid;
}
public bool CanDelete(RoleView view)
{
Boolean isValid = ModelState.IsValid;
isValid &= IsAllowedAction(view, "CanDelete");
return isValid;
}
public Boolean CanEdit(RoleView view)
{
Boolean isValid = ModelState.IsValid;
isValid &= IsUniqueRole(view);
isValid &= IsAllowedAction(view, "CanEdit");
return isValid;
}
private Boolean IsUniqueRole(RoleView view)
{
Boolean isUnique = !UnitOfWork
.Select<Role>()
.Any(role =>
role.Id != view.Id &&
role.Name.ToLower() == view.Name.ToLower());
if (!isUnique)
ModelState.AddModelError<RoleView>(role => role.Name, Validations.RoleNameIsAlreadyUsed);
return isUnique;
}
private Boolean IsAllowedAction(RoleView view, string caller)
{
if (view.CreatedBy != HttpContext.Current.User.Identity.Name)
{
ModelState.AddModelError<RoleView>(role => role.Name, Validations.RoleNameIsAlreadyUsed);
return false;
}
if (DateTime.Now.Subtract(view.CreationDate).TotalDays > 1)
{
ModelState.AddModelError<RoleView>(role => role.Name, Validations.RoleNameIsAlreadyUsed);
return false;
}
if (DateTime.Now.Subtract(view.CreationDate).TotalHours > 2 && caller == "CanEdit")
{
ModelState.AddModelError<RoleView>(role => role.Name, Validations.RoleNameIsAlreadyUsed);
return false;
}
if (DateTime.Now.Subtract(view.CreationDate).TotalHours > 1 && caller == "CanDelete")
{
ModelState.AddModelError<RoleView>(role => role.Name, Validations.RoleNameIsAlreadyUsed);
return false;
}
return true;
}
}
AF Matambo
modified 13-Jun-15 1:55am.
|
|
|
|
|
1) Yes you can, by changing Validator.cs.t4 and ValidatorTests.cs.t4 files accordingly.
2) In your case it would be RoleValidatorTests class.
modified 25-Mar-21 21:01pm.
|
|
|
|
|
Thank you so much, for your replay.
AF Matambo
|
|
|
|
|
What are good practices in model first approach for naming classes which have a data base schema name? For example HumanResources_Departments, is it mandatory to put the schema name, in the configuration class do I need to put the schima argument? Is there any performance penalties for suppressing the schema name or any malfunctioning derived from it.
internal class HumanResources_DepartmentConfiguration : EntityTypeConfiguration<HumanResources_Department>
{
public HumanResources_DepartmentConfiguration(string schema = "HumanResources")
{
ToTable(schema + ".Department");
HasKey(x => x.DepartmentId);
Property(x => x.DepartmentId).HasColumnName("DepartmentID").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
Property(x => x.Name).HasColumnName("Name").IsRequired().HasMaxLength(50);
Property(x => x.GroupName).HasColumnName("GroupName").IsRequired().HasMaxLength(50);
Property(x => x.ModifiedDate).HasColumnName("ModifiedDate").IsRequired();
}
}
AF Matambo
|
|
|
|
|
Usually model classes are just short singular nouns, while table names are they plural forms (EF handles this automatically most of the time).
As for custom schema and table names, it can be defined on your model class like this.
[Table("Department", Schema = "HumanResources")]
public class Departments
{
}
Or you could change schema for all tables, if that's what you want, like this:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.HasDefaultSchema("HumanResources");
}
There aren't any performance penalties or malfunctioning by using different schemas.
modified 25-Mar-21 21:01pm.
|
|
|
|
|
Thank you so much, for your replay.
AF Matambo
|
|
|
|
|
For getting the current logged in user what is good practice,
HttpContext.Current.User.Identity.Name or
Thread.CurrentPrincipal.Identity.Name , can you explain to me why.
AF Matambo
|
|
|
|
|
HttpContext.Current.User.Identity.Name is the current logged in user in your web app. So this is the one which should be used.
Thread.CurrentPrincipal applies only when the <authentication mode="windows">. Normally this is being used with Windows based applications like WinForms, WPF, etc.
Other than that, you should avoid using static HttpContext.Current property, because it will not exist in the next major release of MVC.
modified 25-Mar-21 21:01pm.
|
|
|
|
|
Hello Muchiachio.
I'm a novice programmer but I have a nose to smell that this template was very well cooked and in a luxury oven and is a very good starting point and also an important source of learning. It is unique in its kind, especially because of the ease it provides when coming to renaming the application name. Again thank you very much Muchiachio for your generosity for sharing and supporting this template.
Now, given that we have not yet a step by step tutorial for the implementation of this starter Project, I want to contribute to create that tutorial that is why I believe that with your help Muchiachio and all they are interested in contributing, together we will create a tutorial of life cycle involved in the creation of an application using this template.
I propose that we use the method of questions and answers for that purpose, questions will be made intentionally from the point of view of a novice programmer to make them as useful as possible for those who have just started in the world of programming, and I'll compile all responses and with them create the tutorial, after that I will going to share that tutorial as a complementing part of the documentation of this template.
As such, we will start from the point where we ended when we have followed the instructions and guidelines of the recommended configurations in the article accompanying the template, which made that we have ended this step with a running and full operational multipage MVC application.
To make more interesting, the practical exercise of learning the implementation of this template, we will create a fully functional business application to manage the AdventureWorks database and deployment and localize it for 8 languages (English USA, Spanish, Portuguese, French, Italian, German and English UK and Lithuanian which are already implemented).
If possible, the application should have implemented the possibility of printing reports, make certain dashboard views of the AdventureWorks database, create an internal email for communication of incidents among users, etc.
So let me write down the basic Requirements of the application
1- Simple and attractive lending page (already implemented)
2- All user mast be logged in and have been assigned to any application role in order to taking any Action in the application (already implemented)
3- The user account should be created by a System Administrator or the Human resources manager who will assign the respective role to the User Account. (already implemented)
4- In the lending home page should be implemented the greeting message like “you are logged in as … or Well come …”
5- The site Map navigation should show the real point where we are in the application site map navigation, for example: Home -> Administration -> Accounts
6- After the user have ended his contract in the company the associated user account should be denied to access the application
7- For compliance with the laws and legal regulations all CRUD operations will be validated and authorized only to registered users in their role, no one is allowed to manipulate some ones else records.
a. The Edit and Delete action must be validated according to:
i. Edit and Delete are allowed only if the creator user is same to logged in user
ii. Edit and Delete are allowed if there is no more than one day from a created date time
iii. The edit action is allowed only if there is no more than 4 hour from a created date time
iv. The delete action can be accomplished only if there is no more than 1 hour from a created date time
8- The application should be localized in the following languages:
a. English UK (already implemented)
b. English USA
c. Spanish
d. Portuguese
e. French
f. Italian
g. German
h. Lithuanian (already implemented)
9- Should be implemented Dash boarding functionality for logging and others
10- Should be implemented Printing functionality
11- Should be implemented internal email for incidence communication between application user
AF Matambo
modified 13-Jun-15 0:18am.
|
|
|
|
|