I have tables, to which I can send data, everything is set up, now I only need to understand, how to send data to view. When I want to get data using Model word, I'm getting error: NullReferenceException: Object reference not set to an instance of an object.
index.cshtml
#model FaqVM
#{
Layout = "_Layout";
}
#Model.MainCategoryTitle // Error
Faq.cs
public class Faq : CanBeLocalized, IHaveIntegerId, ICanProvideCreatedTime, IHaveConcurrencyToken
{
public int Id { get; set; }
[Localize] public string MainCategoryTitle { get; set; }
public DateTime Created { get; set; } = DateTime.Now;
public string ConcurrencyToken { get; set; }
public DateTime? Disabled { get; set; }
public int SOrder { get; set; } = 0;
public DateTime? Updated { get; set; }
public ICollection<FaqSubcategory> FaqSubcategories { get; set; } = new HashSet<FaqSubcategory>();
}
FaqVM.cs
public class FaqVM
{
public string MainCategoryTitle { get; set; }
public List<FaqSubcategory> FaqSubcategories { get; set; }
}
public class CmsController : Controller
{
protected ILocale _locale;
protected ICacheManager _cacheManager;
protected RegionProvider _regionProvider;
protected IViewRenderService _viewRenderService;
private IServiceProvider _serviceProvider;
//...
}
public class FaqController : CmsController
{
private readonly Faq _faq;
public FaqController(
RegionProvider regionProvider,
ILocaleAccessor localeAccessor,
ILiteralProvider literalProvider,
CartRepo cartRepo,
IServiceProvider serviceProvider,
Faq faq) : base(serviceProvider)
{
_faq = faq;
}
public async Task<IActionResult> Index()
{
var vm = new FaqVM
{
MainCategoryTitle = _faq.MainCategoryTitle,
FaqSubcategories = _faq.FaqSubcategories.ToList()
};
return View(vm);
}
}
Inside your Index() method in your FaqController you need to create your ViewModel as fx
var vm = new FaqVM(){
MainCategoryTitle = "test",
FaqSubcategories = new List<FaqSubcategory>(){ new FaqSubcategory() }
}
and then you need to pass the ViewModel to the return part of your Index method:
return View(vm);
Typically you would create your vm from some data from a database or some user input.
Related
This is my Model in Model project
public class CompanyName
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime CreateDate { get; set; }
public DateTime ModifyDate { get; set; }
public ICollection<CarModel> CarModels { get; set; }
public ICollection<CreateYear> CreateYear { get; set; }
public ICollection<Diversity> Diversities { get; set; }
public ICollection<CarPrice> CarPrices { get; set; }
}
and this is ViewModel for that
public class CompanyNameVM
{
public int Id { get; set; }
public string Name { get; set; }
}
Also this is my Code for p=mapping in ViewModel Project
public class MiMapping:Profile
{
public MiMapping()
{
CreateMap<Task<CompanyName>, Task<CompanyNameVM>>().ReverseMap();
}
}
after that for use it in Api I use this block
[Route("api/[controller]")]
[ApiController]
public class CompanyNameController : ControllerBase
{
private ICompanyNameRepository _companyNameRepository;
private IMapper _mapper;
public CompanyNameController(ICompanyNameRepository companyNameRepository,IMapper mapper)
{
_companyNameRepository = companyNameRepository;
_mapper = mapper;
}
[HttpGet]
public async Task<IActionResult> GetCarCompanyAsync()
{
var cmObj = await _companyNameRepository.GetAllAsync();
var cvvm = new List<CompanyNameVM>();
foreach (var obj in cmObj)
{
cvvm.Add(_mapper.Map<CompanyNameVM>(obj));
}
return Ok( cvvm);
}
}
after run when I call -
http://localhost:53199/api/companyName
got this error
AutoMapperMappingException: Missing type map configuration or unsupported mapping.
Mapping types:
Object -> CompanyNameVM
System.Object -> MI.ViewModel.CompanyNameVM
It worked fine until I add Id in My ViewModel.
how can I resolve that
If you want to create a map between CompanyName and CompanyNameVM then do it like -
CreateMap<CompanyName, CompanyNameVM>().ReverseMap();
No need to involve Task in mapping.
Also, no need to manually iterate over the CompanyName objects and map one at a time. You can simplify your controller code as -
[HttpGet]
public async Task<IActionResult> GetCarCompanyAsync()
{
var cmObj = await _companyNameRepository.GetAllAsync();
var cvvm = _mapper.Map<IEnumerable<CompanyNameVM>>(cmObj);
return Ok(cvvm);
}
I'm assuming _companyNameRepository.GetAllAsync() is returning an IEnumerable<CompanyName> in some form.
I have a simple ASP.NET Core (2.1) API that implements get & post methods with objects of this class:
public class Command
{
public uint id { get; set; }
public string command { get; set; }
public List<Client> clients { get; set; }
}
public class Client
{
public uint id { get; set; }
public string nameofpc { get; set; }
}
public class CommandContext : DbContext
{
public CommandContext(DbContextOptions<CommandContext> options) : base(options) { }
public DbSet<Command> Commands { get; set; }
}
I send POST request with this entity:
var command = new Command()
{
command = "/start^cmd.exe",
clients = new List<Client>()
{
new Client()
{
nameofpc = "Zerumi"
}
}
};
// Converting to JSON and sending to api...
In CommandController.cs located this code:
[Route("api/[controller]")]
[ApiController]
public class CommandController : ControllerBase
{
private readonly CommandContext _context;
public CommandController(CommandContext context)
{
_context = context;
}
[HttpGet]
public async Task<ActionResult<IEnumerable<Command>>> GetCommands()
{
return await _context.Commands.ToListAsync();
}
[HttpPost]
public async Task<ActionResult<Command>> PostCommand([FromBody] Command item)
{
_context.Commands.Add(item);
await _context.SaveChangesAsync();
return CreatedAtAction(nameof(GetCommand), new { item.id }, item);
}
}
The item parameter of the postcommand method is no different from what was sent. However, if i send GET request to /command after saving, i will get this:
[{"id":1,"command":"/start^cmd.exe","clients":null}]
Why colleŃtion is null and what i need to do for good entity saving?
To me, it seems that something is missing, but maybe you configure stuff in OnModelCreating, hard to tell when I don't have your code. And you should use Pascal-casing in your EF-code and replace uint with int.
Then you should add DTO-classes (model-classes) for both Command and Client. Decorate each property in DTO with e.g.
[JsonProperty("command")]
in order to maintain correct casing (camel-casing).
public class Command
{
public uint id { get; set; }
public string command { get; set; }
public List<Client> clients { get; set; }
}
public class Client
{
public int CommandId { get; set; } // foreign key
[ForeignKey(nameof(CommandId))]
public Command Command { get; set; }
public uint id { get; set; }
public string nameofpc { get; set; }
}
I have a request like this:
filter[logic]:and
filter[filters][0][value]:a
filter[filters][0][operator]:startswith
filter[filters][0][field]:result
filter[filters][0][ignoreCase]:true
I need to receive it on the Controller but I don't know exactly how. I have tried this view model:
{
public class SearchFilterViewModel
{
public string logic { get; set; }
public List<SearchFilterFiltersViewModel> filters { get; set; }
}
public class SearchFilterFiltersViewModel
{
public string value { get; set; }
//public string operator { get; set; }
public string field { get; set; }
public bool ignoreCase { get; set; }
}
}
But the Controller receives it all null. operator property is commented because operator is a reserved keyword, I don't know how to make Asp.Net to use it. And I don't know if this is the cause of the problem.
Note that I can't change the request body pattern because it comes from this Kendo Widget.
This is my Controller(test version):
public ActionResult Text(SearchFilterViewModel filter)
{
return Json("", JsonRequestBehavior.AllowGet);
}
Here is working solution
Model:
public class SearchFilterViewModel
{
public string logic { get; set; }
public List<SearchFilterFiltersViewModel> filter { get; set; }
}
public class SearchFilterFiltersViewModel
{
public string value { get; set; }
public string oper { get; set; }
public string field { get; set; }
public bool ignoreCase { get; set; }
}
Then you can write custom IValueProvider where you can override usual parsing mechanism like this:
public class KendoValueProvider : NameValueCollectionValueProvider
{
public KendoValueProvider(NameValueCollection originalCollection)
: base(UpdateCollection(originalCollection), CultureInfo.InvariantCulture)
{
}
private static NameValueCollection UpdateCollection(NameValueCollection collection)
{
NameValueCollection result = new NameValueCollection();
foreach (string key in collection.Keys)
{
// ignore all other request
if (!key.StartsWith("filter"))
return null;
var newKey = key
.Replace("[filters]", string.Empty)
.Replace("filter[logic]", "logic")
.Replace("[value]", ".value")
.Replace("[operator]", ".oper")
.Replace("[field]", ".field")
.Replace("[ignoreCase]", ".ignoreCase");
var value = collection[key];
result.Add(newKey, value);
}
return result;
}
}
Then you need to write ValueProviderFactory that will register this ValueProvider like this:
public class KendoValueProviderFactory : ValueProviderFactory
{
public override IValueProvider GetValueProvider(ControllerContext controllerContext)
{
return new KendoValueProvider(controllerContext.HttpContext.Request.QueryString);
}
}
And the last step is just register it in Global.asax file
ValueProviderFactories.Factories.Add(new KendoValueProviderFactory());
And sample Action
[HttpGet]
public ActionResult Index(SearchFilterViewModel model)
{
return Json(model, JsonRequestBehavior.AllowGet);
}
I have four classes as following:
public class Section
{
public int SectionId { get; set; }
public string Name { get; set; }
public string Title { get; set; }
public string MetaTag { get; set; }
public string MetaDescription { get; set; }
public string UrlSafe { get; set; }
public string Header { get; set; }
public string ImageName { get; set; }
}
public interface ISectionRepository
{
List<Section> GetAllSections();
}
public class SectionRepository : ISectionRepository
{
Context context = new Context();
public List<Section> GetAllSections()
{
return context.Sections.ToList();
}
}
public class SectionApplication
{
SectionRepository sectionRepo = new SectionRepository();
public List<Section> GetAllSections()
{
return sectionRepo.GetAllSections();
}
}
And in my controller, I have
public class SectionController : Controller
{
SectionApplication sectionApp = new SectionApplication();
public ActionResult Index()
{
return View(sectionApp.GetAllSections());
}
}
Now, I want to do cache sections on memory for a specific time in order to read sections from cache if it exists, else read it from database.
Simple possible approach, you can use MemoryCache, the code will look like:
public List<Section> GetAllSections()
{
var memoryCache = MemoryCache.Default;
if (!memoryCache.Contains("section"))
{
var expiration = DateTimeOffset.UtcNow.AddMinutes(5);
var sections = context.Sections.ToList();
memoryCache.Add("section", sections, expiration);
}
return memoryCache.Get("section", null);
}
You do the caching by adding a new class with a timeout. When you read the first time, you read directly from the database and write the data into a property of the new class and make a timestamp. In the next read operation, you check your new class to see if the timeout has been reached. If not, you read the data from the new class. Otherwise, you read from the database and put it into the cache class and update the timeout.
public interface IRepositoryCollection
{
DateTime dateCreated { get; set; }
}
public class Cache<T> : Dictionary<string, T>
{
private int cacheDuration = 1;
private int maxCacheSize = 20;
public Cache(int cacheDuration, int maxCacheSize)
{
this.cacheDuration = cacheDuration;
this.maxCacheSize = maxCacheSize;
}
public new void Add(string key, T invoices)
{
base.Add(key, invoices);
RemoveOld();
RemoveOldest();
}
public void RemoveOld()
{
foreach (KeyValuePair<string, T> cacheItem in this)
{
Interfaces.IRepositoryCollection currentvalue = (Interfaces.IRepositoryCollection)cacheItem.Value;
if (currentvalue.dateCreated < DateTime.Now.AddHours(-cacheDuration))
{
this.Remove(cacheItem.Key);
}
}
}
public void RemoveOldest()
{
do
{
this.Remove(this.First().Key);
}
while (this.Count > maxCacheSize);
}
}
public class ProformaInvoiceCache
{
private static Cache<ProformaInvoices> cache = new Cache<ProformaInvoices>(1, 20);
public static string AddInvoiceCollection(ProformaInvoices invoices)
{
// Adds invoice collection to static instance of cache, returns guid required to retrieve item from cache
return cache.Add(invoices);
}
public static ProformaInvoices GetInvoiceCollection(string guid)
{
// Gets invoice collection from cache corresponding to passed guid
return cache.Get(guid);
}
}
My task is to show multiple models into a single view.I've created a ViewModel for my requirement but I'm not meeting my requirement.
please have a look into the below code and rectify me where m i going wrong ???
public partial class StudentsDetail
{
public int StudentID { get; set; }
public int ParentID { get; set; }
public string StudentName { get; set; }
public string Gender { get; set; }
public string FatherName { get; set; }
public string MotherName { get; set; }
public Nullable<System.DateTime> DateOfBirth { get; set; }
public virtual ParentsDetail ParentsDetail { get; set; }
public virtual SchoolDetail SchoolDetail { get; set; }
}
//Model 2
public partial class ParentsDetail
{
public ParentsDetail()
{
this.StudentsDetails = new HashSet<StudentsDetail>();
}
public int ParentID { get; set; }
public string Occupation { get; set; }
public string Organization { get; set; }
public string AnnualIncome { get; set; }
public virtual ICollection<StudentsDetail> StudentsDetails { get; set; }
}
//ViewModel Which I have created
public class ParentsInformationViewModel
{
public List<StudentsDetail> StudentsDetails { get; set; }
public List<ParentsDetail> ParentsDetails { get; set; }
public ParentsInformationViewModel(List<StudentsDetail> _studentDetails, List<ParentsDetail> _parentsDetails) //Should i pass all the required parameters that i want to display in view ????
{
StudentsDetails = _studentDetails;
ParentsDetails = _parentsDetails;
}
//And finally this is my method defined in the StudentController (Have i defined it in a right place/way??)
public ActionResult StudentViewModel()
{
ViewBag.ParentsDetail = new ParentsDetail(); //ParentsDetail is my controller
List<StudentsDetail> studentListObj = StudentsDetailsDAL.GetStudentDetails();
List<ParentsInformationViewModel> ParentInfoVMObj = new List<ParentsInformationViewModel>();
//foreach (var student in studentListObj)
//{
// ParentInfoVMObj.Add(new ParentsInformationViewModel(student.StudentID, student.ParentID));
//}
//ParentInfoVMObj.Add(ParentInfoVMObj); /// don't know how to call the required viewmodel
return View(ParentInfoVMObj);
}
I know that the above method of a ViewModel is wrong but how to use it or where am i going wrong I can't get.
I want to display the ViewModel in the view as a detailed view .
Please, correct me as I'm a starter in MVC3 .
Thanks In Advance!!
In your controller, define your action method as follows.
public ActionResult ParentsDetails()
{
var studentDetails = new List<StudentDetail>();
var parentDetails = new List<ParentsDetail>();
// Fill your lists here, and pass them to viewmodel constructor.
var viewModel = new ParentsInformationViewModel(studentDetails, parentDetails)
// Return your viewmodel to corresponding view.
return View(viewModel);
}
In your view define your model.
#model MySolution.ViewModels.ParentsInformationViewModel
Is there in your view declared that you are receiving model of type
In view:
#model IEnumerable<ParentsInformationViewModel>