DynamicComponent send value from child to the parent - asp.net-core

I have a class that represents the necessary data for creating a DynamicComponent:
public class ComponentMetadata
{
public string? Name { get; set; }
public Dictionary<string, object> Parameters { get; set; } =
new Dictionary<string, object>();
}
I have a custom table component that uses ComponentMetadata to add some dynamic component to the table:
TableTemplate.razor:
<table class="table">
<thead>
<tr>#TableHeader</tr>
</thead>
<tbody>
#foreach (var RowTemplateConfig in RowTemplateConfigs)
{
if (RowTemplateConfig.DataItem is not null)
{
<tr>
<td> #RowTemplateConfig.DataItem </td>
#if(RowTemplateConfig.ComponentMetadata is not null)
{
<td>
<DynamicComponent
Type= RowTemplateConfig.ComponentMetadata.Name
Parameters= RowTemplateConfig.ComponentMetadata.Parameters />
</td>
}
</tr>
}
}
</tbody>
</table>
#code {
public class RowTemplateConfig
{
public ComponentMetadata ComponentMetadata { get; set;}
public string DataItem { get; set; }
}
[Parameter]
public RenderFragment? TableHeader { get; set; }
[Parameter]
public List<RowTemplateConfig> RowTemplateConfigs {get; set;}
}
I have also other custom components for example Button custom component:
MyButton.razor
<button type="button"
class="#Style"
#onclick="BtnClick">
#Text
</button>
#code {
[Parameter]
public string Style { get; set; }
[Parameter]
public string Text { get; set; }
[Parameter]
public EventCallback<object> OnBtnClick { get; set; }
private async Task BtnClick(object item)
{
await OnBtnClick.InvokeAsync(item);
}
}
I want to use my TableTemplate.razor in some razor page:
pets1.razor
#page "/pets1"
<h1>Pets</h1>
<TableTemplate RowTemplateConfigs =RowTemplateConfigs TItem =string>
<TableHeader>
<th>Name</th>
</TableHeader>
</TableTemplate>
#code {
private List<RowTemplateConfig> RowTemplateConfigs = new()
{
RowTemplateConfig = new ()
{
DataItem = "Bigglesworth",
ComponentMetadata = new()
{
Name= typeof(MyButton).
Parameters = new Dictionary<string, object>()
{
{ nameof(MyButton.Style), "btn btn-outline-success" }
{ nameof(MyButton.OnBtnClick), EventCallback.Factory.Create<object>(this, OnTestClick)},
{ nameof(MyButton.Text), "Hi"}
}
}
},
RowTemplateConfig = new ()
{
DataItem = "Saberhagen",
ComponentMetadata = new()
{
Name= typeof(MyButton).
Parameters = new Dictionary<string, object>()
{
{ nameof(MyButton.Style), "btn btn-outline-success" }
{ nameof(MyButton.OnBtnClick), EventCallback.Factory.Create<object>(this, OnTestClick)},
{ nameof(MyButton.Text), "Hi"}
}
}
},
//rest of the lest ...
}
private async Task OnTestClick(object sender)
{
// I want to catch the name of the pet here when user click on the button
await Task.Delay(20);
}
}
My Question:
When user clicks on MyButton in TableTemplate in pets1.razor I want to catch the element (name of pet) in the event OnTestClick.
Thanks and sorry for long question, I appreciate any suggestion.

You need to add a Pet Name parameter to the button component, load it and then submit the property back on the callback event.
Here's a modified version of your code (with a few typo and type fixes). Note: I code with Nullable enabled.
ComponentMetadata
public class ComponentMetadata
{
public Type Name { get; set; } = default!;
public Dictionary<string, object> Parameters { get; set; } =
new Dictionary<string, object>();
}
MyButton.razor
<button type="button" class="#Style" #onclick=BtnClick>
#Text
</button>
#code {
[Parameter] public string? Style { get; set; }
[Parameter] public string? Name { get; set; }
[Parameter] public string? Text { get; set; }
[Parameter] public EventCallback<string> OnBtnClick { get; set; }
private async Task BtnClick()
=> await OnBtnClick.InvokeAsync(this.Name);
}
And then the rest of the code rolled into my test page:
#page "/"
#foreach (var component in myDynamicComponents)
{
<DynamicComponent Type="#component.ComponentMetadata.Name" Parameters=component.ComponentMetadata.Parameters />
}
<div class="p-2 m-2">
<strong>Message:</strong> #message
</div>
#code {
private string message = string.Empty;
private RowTemplateConfig GetRowTemplate(string petName)
=> new RowTemplateConfig
{
DataItem = petName,
ComponentMetadata =
new ComponentMetadata()
{
Name = typeof(MyButton),
Parameters = new Dictionary<string, object>()
{
{ nameof(MyButton.Style), "btn btn-outline-success ms-1" },
{ nameof(MyButton.Name), petName },
{ nameof(MyButton.OnBtnClick), EventCallback.Factory.Create<string>(this, OnTestClick)},
{ nameof(MyButton.Text), $"Hi {petName}"}
}
}
};
private List<RowTemplateConfig> myDynamicComponents => new List<RowTemplateConfig> {
GetRowTemplate("Ginger"),
GetRowTemplate("Tiger"),
GetRowTemplate("Felix")
};
private async Task OnTestClick(string name)
{
await Task.Delay(20);
message = $"{name} Clicked at {DateTime.Now.ToLongTimeString()}";
}
public class RowTemplateConfig
{
public ComponentMetadata ComponentMetadata { get; set; } = default!;
public string? DataItem { get; set; }
}
}

Related

How to re-Render Blazor Component witch Render by RenderFragment or re-Bind Resource for Child who Render by RenderFragment

Question :
I am looking for how to let "RenderFragment" can re-Render or re-Binding Resource .
Environment:
VS2019 Preview , .net core 6 preview (I think it is not different with 5)
What I Had Try :
My Razor Component page has a selection and a button ,
Selection will get default resource when page first render ,
Button Click Cvent should change the resource of Selection .
This is What I prefer for correct result
But Actually ,
Resource is not changing when I Using RenderFragment to create component .
Resource is not changing.
I Stop at FabArea.razor to check if button click changed oResource .
Stop at Button Clicked.
I tried to add StateHasChanged() in my code , but it didn't help when oResource has changed .
oResource Changed into B , by Selection's Resource is still same.
In some reason I have to make each "Area" ,"selection" and "button" into different component .
Here is My code .
Parent Component : DyResource.Razor
#page "/DyResource"
<h3>DyResource</h3>
<p>You Just Select : #SelectedValue </p>
<p>isDefault Resource : #(isDefaultResource?"Default Value":"Not Default Value") </p>
<p>Resource[0]: #(oResource.First().id.ToString())</p>
<FabArea Componets="#liComponets"></FabArea>
#code {
public List<iFabComponet> liComponets { get; set; }
public List<Selection> oResource { get; set; }
public string SelectedValue { get; set; }
public bool isDefaultResource { get; set; } = true;
public class Selection
{
public string id { get; set; }
public string text { get; set; }
}
public class iFabComponet
{
public Type Type { get; set; }
public string Row { get; set; }
public string Length { get; set; }
public string Seq { get; set; }
public RenderFragment Control { get; set; }
public Dictionary<string, object> Dic { get; set; }
public object TComponent { get; set; }
}
protected override void OnInitialized()
{
DefaultResource(); //Set oResource
CreateComponent();
}
//Selection Resource When First Render Pages
private void DefaultResource()
{
oResource = new List<Selection>
{
new Selection { id = "A01", text = "A01" },
new Selection { id = "A02", text = "A02" },
new Selection { id = "A03", text = "A03" },
new Selection { id = "A04", text = "A04" },
new Selection { id = "A05", text = "A05" }
};
//StateHasChanged();
}
// Selection Resource When Button Click
private void ChangedResource()
{
oResource = new List<Selection>()
{
new Selection { id = "B01", text = "B01" },
new Selection { id = "B02", text = "B02" },
new Selection { id = "B03", text = "B03" },
new Selection { id = "B04", text = "B04" },
new Selection { id = "B05", text = "B05" }
};
//StateHasChanged();
}
//Create KeyValuePair for Child Components
private void CreateComponent()
{
List<iFabComponet> FCs = new List<iFabComponet>();
var DDLDic = new Dictionary<string, object>();
DDLDic.Add("Label", "Type");
DDLDic.Add("Resource", oResource);
DDLDic.Add("TextField", "id");
DDLDic.Add("ValueField", "text");
DDLDic.Add("Enabled", true);
DDLDic.Add("Id", "ddlType");
DDLDic.Add("Width", "100%");
DDLDic.Add("ResultValueChanged", EventCallback.Factory.Create<System.String>(this, str => TypeSelected(str)));
iFabComponet FirstCom = new iFabComponet() { Type = typeof(FabDDL<string, Selection>), Row = "1", Length = "6", Seq = "1", Dic = DDLDic };
liComponets.Add(FirstCom);
var btnDic = new Dictionary<string, object>();
btnDic.Add("ButtonTitle", "Get Data");
btnDic.Add("isNeedPad", true);
btnDic.Add("PadLength", 4);
btnDic.Add("OnClick", EventCallback.Factory.Create<System.String>(this, str => BtnClick()));
iFabComponet SecCom = new iFabComponet() { Type = typeof(FabButton), Row = "2", Length = "6", Seq = "2", Dic = btnDic };
liComponets.Add(SecCom);
}
//Selection Event
private void TypeSelected(string x)
{
SelectedValue = x;
}
//Button Event
private void BtnClick()
{
if (isDefaultResource)
{
ChangedResource();
isDefaultResource = false;
}
else
{
DefaultResource();
isDefaultResource = true;
}
CreateComponent();
StateHasChanged();
}
}
FabArea.Razor (Area to show and Render Child Component)
#using System.Linq.Expressions
<div class="card">
<div class="card-body">
#foreach (var item in Contents)
{
#item
;
}
</div>
</div>
#code {
[Parameter]
public List<iFabComponet> Componets { get; set; }
public List<RenderFragment> Contents { get; set; }
protected override void OnInitialized()
{
if (Componets.Count() > 0 && Componets != null)
{
CreateFragment();
}
}
public async void CreateFragment()
{
int iComponent = 0;
List<RenderFragment> RFTs = new List<RenderFragment>();
Contents = new List<RenderFragment>();
int iContent = 1;
foreach (var area in Componets)
{
RenderFragment renderFragment = (builder) =>
{
builder.OpenComponent(iComponent, area.Type);
//Using For Checking Resource .
foreach (var item in area.Dic)
{
var q = item.Key;
var w = item.Value;
}
builder.AddMultipleAttributes(iContent, area.Dic);
builder.CloseComponent();
};
Contents.Add(renderFragment);
}
StateHasChanged();
}
}
Here is Selection Component and Button Component .
FabDDL.razor
#typeparam T
#typeparam TResource
<div class="row">
<label class="col-md-2">#Label</label>
<div class="col-md-5">
<select class="selection" id="#id" disabled="#(!Enabled)" #onchange="#(() => ResultValueChanged.InvokeAsync())">
<option></option>
#if (Resource != null)
{
#foreach (var item in Resource)
{
<option value="#(item.GetType().GetProperty(ValueField).GetValue(item))">#(item.GetType().GetProperty(TextField).GetValue(item))</option>
}
}
</select>
</div>
</div>
#code {
[Parameter] public string Label { get; set; }
//[Parameter] public T ResultValue { get; set; }
[Parameter] public List<TResource> Resource { get; set; }
[Parameter] public string DefaultText { get; set; } = "Select an Option";
[Parameter] public string id { get; set; } = "DropDownList" + Guid.NewGuid().ToString();
[Parameter] public string Width { get; set; } = "100 %";
[Parameter] public bool Enabled { get; set; }
[Parameter] public string TextField { get; set; }
[Parameter] public string ValueField { get; set; }
[Parameter] public EventCallback<T> ResultValueChanged { get; set; }
}
<style>
.selection {
width: 100%;
height: 100%;
padding-left: 15px;
}
</style>
FabButton.razor
#if (isNeedPad){<div class="#PadRowClass"></div>}
<div class="col-md-2 pt-3 middle">
<button class="btn btn-info" type="#ButtonType" #onclick="#(() => OnClick.InvokeAsync())">#ButtonTitle</button>
</div>
#code {
[Parameter] public string ButtonTitle { get; set; } = "Click ME!";
[Parameter] public string ButtonType { get; set; } = "button";
[Parameter] public EventCallback<string> OnClick { get; set; }
[Parameter] public bool isNeedPad { get; set; } = false;
[Parameter] public int PadLength { get; set; } = 1;
public string PadRowClass { get; set; }
protected override void OnInitialized()
{
PadRowClass = "col-md-" + PadLength.ToString();
base.OnInitialized();
}
}

Object reference not set to an instance of an object in Razor

I'm new to Razor and I'm getting this error when trying to loop through a list of objects.
This is my View:
#page
#model QuizModel
#{
ViewData["Title"] = "Quiz Page";
}
<div class="text-center">
<h1 class="display-4">Thanks for checking my first website out, #Model.Visitor.Name. Are you ready?</h1>
<p>Let's see how much you know about me.</a>.</p>
</div>
<div class="text-center">
<h1 class="display-4">Welcome</h1>
<form method="post">
#foreach (var question in #Model.QuestionList)
{
<label>#question.Query</label>
}
<button type="submit">Send</button>
</form>
</div>
This is the .cs
namespace myquiz.Pages
{
public class QuizModel : PageModel
{
[ViewData]
[BindProperty]
public string Name { get; set; }
[BindProperty]
public Visitor Visitor { get; set; }
public List<Question> QuestionList { get; set; }
public void OnGet()
{
var quizService = new QuizService();
///QuestionList = new List<Question>();
QuestionList = quizService.GetQuestions();
}
public void OnPost()
{
Name = Visitor.Name;
}
}
}
Here's the service
public class QuizService
{
public List<Question> GetQuestions()
{
return new List<Question>()
{
new Question()
{
Id=1,
Query = "What's my favourite band?",
Option1 = "Beatles",
Option2 = "Rolling Stones",
Option3 = "Led Zeppelin",
Answer = "Led Zeppelin"
},
new Question()
{
Id=2,
Query = "What's my favourite colour?",
Option1 = "Pink",
Option2 = "Yellow",
Option3 = "Maroon",
Answer = "Pink"
},
};
}
}
I tried to initialise the list in the comment but It did't work either :(
Thanks!
It's better to see the implementation of quizService.GetQuestions() method. But you can check the variable after the method.
QuestionList = quizService.GetQuestions();
if (QuestionList is null)
QuestionList = new List<Question>();
It's better to do this check in the GetQuestions() method.
You need to initialize both Visitor and QuestionList,because you use them in your view.
You can change
[BindProperty]
public Visitor Visitor { get; set; }
public List<Question> QuestionList { get; set; }
to
[BindProperty]
public Visitor Visitor { get; set; } = new Visitor();
[BindProperty]
public List<Question> QuestionList { get; set; } = new List<Question>();
So that you don't need to initialize in OnGet.
Update:
DI for service:
Startup:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddScoped<QuizService, QuizService>();
}
PageModel:
public readonly QuizService quizService;
public QuizModel(QuizService q){
quizService = q;
}
public void OnGet()
{
QuestionList = quizService.GetQuestions();
}

How to deal with this decimal error for a price?

I'm working on this app that should show on "localhost/catalog" some data. I have a library for the models and for the services that the application might use. I am getting this error:
InvalidOperationException: The property 'Price' is not a navigation
property of entity type 'StoreAsset'. The 'Include(string)' method can
only be used with a '.' separated list of navigation property names.Microsoft.EntityFrameworkCore.Query.Internal.IncludeCompiler.WalkNavigations(IEntityType entityType, IReadOnlyList<string> navigationPropertyPaths, IncludeLoadTree includeLoadTree, bool shouldThrow)
Here is the code that I'm using (controller, models and view) and the service methods on bottom:
public class CatalogController : Controller
{
private IStoreAsset _assets;
public CatalogController(IStoreAsset assets)
{
_assets = assets;
}
public ActionResult Index()
{
var assetModels = _assets.GetAll();
var listingResult = assetModels
.Select(result => new AssetIndexListingModel
{
Id = result.Id,
Tipology = _assets.GetTipology(result.Id),
Size = _assets.GetSize(result.Id),
Price = decimal.Parse(_assets.GetPrice(result.Id))
});
var model = new AssetIndexModel()
{
Assets = listingResult
};
return View(model);
}
public class AssetIndexListingModel
{
public int Id { get; set; }
public string Size { get; set; }
public decimal Price { get; set; }
public string Tipology { get; set; }
public string ImageUrl { get; set; }
}
public abstract class StoreAsset
{
public int Id { get; set; }
[Required]
public Status Status { get; set; }
[Required]
public decimal Price { get; set; }
public string ImageUrl { get; set; }
}
public class Dress : StoreAsset
{
[Required]
public string Color { get; set; }
[Required]
public string Tipology { get; set; }
[Required]
public string Size { get; set; }
}
#model Models.Catalog.AssetIndexModel
<div id="assets">
<h3></h3>
<div id="assetsTable">
<table class="table table-condensed" id="catalogIndexTable">
<thead>
<tr>
<th>Size</th>
<th>Price</th>
<th>Tipology</th>
</tr>
</thead>
<tbody>
#foreach (var asset in Model.Assets)
{
<tr class="assetRow">
<td class="">
<a asp-controller="Catalog" asp-action="Detail" asp-route-id="#asset.Id">
<img src="#asset.ImageUrl" class="imageCell" />
</a>
</td>
<td class="">#asset.Price</td>
<td class="">#asset.Size</td>
<td class="">#asset.Tipology</td>
</tr>
}
</tbody>
</table>
</div>
public class StoreAssetService : IStoreAsset
{
private Context _context;
public StoreAssetService(Context context)
{
_context = context;
}
public void Add(StoreAsset newAsset)
{
_context.Add(newAsset);
_context.SaveChanges();
}
public IEnumerable<StoreAsset> GetAll()
{
return _context.StoreAssets
.Include(asset => asset.Status)
.Include(asset => asset.Price);
}
public StoreAsset GetById(int id)
{
// Return a query (same as returning GetAll().FirstOrDefault(...))
return _context.StoreAssets
.Include(assets => assets.Status)
.Include(assets => assets.Price)
// So it can return null with no problem
.FirstOrDefault(asset => asset.Id == id);
}
public StoreBranch GetCurrentLocation(int id)
{
throw new NotImplementedException();
}
// To implement and test
public string GetPrice(int id)
{
return _context.Dresses.FirstOrDefault(p => p.Id == id).Price.ToString();
}
public string GetSize(int id)
{
return _context.Dresses.FirstOrDefault(s => s.Id == id).Size;
}
public string GetStatus(int id)
{
throw new NotImplementedException();
}
public string GetTipology(int id)
{
var dress = _context.StoreAssets.OfType<Dress>()
.Where(b => b.Id == id);
// For now return other if it's not a party dress
return dress.Any() ? "Party" : "Other";
}
}
Should I use some ForeignKey attribute or change Price to a string?
Any help would be great thanks
As pointed out in the error message, the Include is for the Navigation property only.
You need to change below:
return _context.StoreAssets
.Include(asset => asset.Status)
.Include(asset => asset.Price);
To:
return _context.StoreAssets
.Include(asset => asset.Status).ToList();
Reference: https://learn.microsoft.com/en-us/ef/core/modeling/relationships#definition-of-terms
https://learn.microsoft.com/en-us/ef/core/querying/related-data
I am having yet another problem. When I go to "localhost/catalog" the page should display all columns/entries that I have in the database but it only displays one column. Is there something wrong in the foreach cicle?

search function in ASP.NET MVC not working properly

i have a student table in my database that i created and i have a view that displays a list of all the students grouped by class... on top of the view i made a textbox and a search button to be able to access the student information faster. The problem is that i when i enter the first name and the last name in the textbox, nothing comes up. When i enter only the first name or only the last name, then it finds it. I'm new to programming and i can't figure out how to make it work. I would really appreciate if someone can help me with this. This is part of my code:
[HttpGet]
public ActionResult ViewStudents()
{
ViewBag.classes = db.Courses.ToList();
var studentCourses = db.StudentCourses.OrderBy(s=>s.Person.FirstName).ToList();
return View(studentCourses);
}
[HttpPost]
public ActionResult ViewStudents(string SearchString)
{
var student=new List<int>();
List<StudentCourse>sc=new List<StudentCourse>();
ViewBag.classes = db.Courses.ToList();
var studentCourse=db.StudentCourses.ToList();
var studentCourses = db.StudentCourses.OrderBy(s => s.Person.FirstName).ToList();
var substring = SearchString.IndexOf(" ").ToString();
if (!string.IsNullOrEmpty(SearchString))
{
student = (from p in db.People
where (p.FirstName.Contains(SearchString)) && (p.LastName.Contains(substring))||((p.FirstName.Contains(SearchString)) || (p.LastName.Contains(SearchString)))
select p.PersonId).ToList();
}
foreach (var s in studentCourse)
{
foreach (var i in student)
{
if (s.StudentId == i)
{
sc.Add(s);
}
}
}
return View(sc);
}
This is my view:
#model List<SchoolFinalProject.Models.StudentCourse>
#using (Html.BeginForm())
{
<div style="font-size:16px;"> <input type="text" id="search" placeholder="search" Name="SearchString" /><span class="glyphicon glyphicon-search"></span>
<input type="submit" value="search"></div>
}
#{
List<int> c = new List<int>();
foreach (var courses in ViewBag.classes)
{
foreach(var s in Model)
{
if(courses.CourseId==s.CourseId)
{
c.Add(courses.CourseId);
}
}
}
}
#foreach (var course in ViewBag.classes)
{
if(c.Contains(course.CourseId))
{
<h2>#course.Name<span>-</span>#course.Gender</h2>
<table class="table table-hover table-bordered table-striped">
<tr><th>First Name</th><th>Last Name</th><th>Email</th><th>Phone Number</th><th>Address</th><th>Date Of Birth</th></tr>
#foreach (var s in Model)
{
if(course.CourseId==s.CourseId)
{
<tr>
<td>#s.Person1.FirstName</td>
<td>#s.Person1.LastName</td>
<td>#s.Person1.Email</td>
<td>#s.Person1.PhoneNumber</td>
<td>#s.Person1.Address</td>
<td>#s.Person1.DateOfBirth</td>
<td>
<span class="glyphicon glyphicon-edit"></span>
#Html.ActionLink("Edit", "Edit","Person", new { id = s.Person1.PersonId }, null) |
<span class="glyphicon glyphicon-trash"></span>
#Html.ActionLink("Details", "Details","Person", new { id = s.Person1.PersonId }, null)
</td>
</tr>
}
}
</table>
}
}
Go to top of page
this is my person Model:
public partial class Person
{
public Person()
{
this.Bonus = new HashSet<Bonu>();
this.ConversationHistories = new HashSet<ConversationHistory>();
this.ConversationHistories1 = new HashSet<ConversationHistory>();
this.EmployeePaymentDetails = new HashSet<EmployeePaymentDetail>();
this.StudentCourses = new HashSet<StudentCourse>();
this.StudentCourses1 = new HashSet<StudentCourse>();
this.TeacherCourses = new HashSet<TeacherCourse>();
this.Reminders = new HashSet<Reminder>();
}
public int PersonId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public string PhoneNumber { get; set; }
public string Address { get; set; }
public Nullable<System.DateTime> DateOfBirth { get; set; }
public PersonType PersonTypeId { get; set; }
public Nullable<System.DateTime> LastModified { get; set; }
public Nullable<int> Gender { get; set; }
public Nullable<int> Status { get; set; }
public string FullName
{
get { return FirstName + ", " + LastName; }
}
public virtual ICollection<Bonu> Bonus { get; set; }
public virtual ICollection<ConversationHistory> ConversationHistories { get; set; }
public virtual ICollection<ConversationHistory> ConversationHistories1 { get; set; }
public virtual ICollection<EmployeePaymentDetail> EmployeePaymentDetails { get; set; }
public virtual ICollection<StudentCourse> StudentCourses { get; set; }
public virtual ICollection<StudentCourse> StudentCourses1 { get; set; }
public virtual ICollection<TeacherCourse> TeacherCourses { get; set; }
public virtual ICollection<Reminder> Reminders { get; set; }
}
}
You might want to try concatenating the first and last name properties in your person model like this:
[Display(Name = "Full Name")]
public string FullName
{
get
{
return LastName + ", " + FirstMidName;
}
}
There is a very good tutorial on what you are trying to do here: https://www.asp.net/mvc/overview/getting-started/getting-started-with-ef-using-mvc/creating-a-more-complex-data-model-for-an-asp-net-mvc-application
Also see this page of same tutorial: https://www.asp.net/mvc/overview/getting-started/getting-started-with-ef-using-mvc/sorting-filtering-and-paging-with-the-entity-framework-in-an-asp-net-mvc-application
As an aside, you might want to check out using the Datatables plugin, which gives you search functionality without have to query your database with each search: https://datatables.net

'HttpPostedFileBase' has no key defined. Define the key for this EntityType

I have create an application to upload image in database
this is my model
[Table("ImageGallery")]
public class ImageGallery
{
[Key]
public int ImageID { get; set; }
public int ImageSize { get; set; }
public string FileName { get; set; }
public byte[] ImageData { get; set; }
[Required(ErrorMessage="Please select Image File")]
public HttpPostedFileBase file { get; set; }
}
this is my database model
public class TPADB : DbContext
{
public DbSet<ImageGallery> imagegallery { get; set; }
}
this is my view
#using (Html.BeginForm("Upload", "ImageUP", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.ValidationSummary(true)
<table>
<tr>
<td>Select File : </td>
<td>
#Html.TextBoxFor(Model => Model.file, new { type="file"})
#Html.ValidationMessage("CustomError")
</td>
<td>
<input type="submit" value="Upload" />
</td>
</tr>
</table>
}
this is my controller
[HttpGet]
public ActionResult Upload()
{
return View();
}
[HttpPost]
public ActionResult Upload(ImageGallery IG)
{
IG.FileName = IG.file.FileName;
//IG.ImageSize = IG.file.ContentLength;
byte[] data = new byte[IG.file.ContentLength];
IG.file.InputStream.Read(data, 0, IG.file.ContentLength);
IG.ImageData = data;
using (TPADB db = new TPADB())
{
db.imagegallery.Add(IG);
db.SaveChanges();
}
return View();
}
but it throughs an error that
"One or more validation errors were detected during model generation:
TPA.Models.HttpPostedFileBase: : EntityType 'HttpPostedFileBase' has no key defined. Define the key for this EntityType.
HttpPostedFileBases: EntityType: EntitySet 'HttpPostedFileBases' is based on type 'HttpPostedFileBase' that has no keys defined."
Figured it out, make the following changes to the model:
public partial class ImageGallery
{
[Key]
public int ImageID { get; set; }
public int ImageSize { get; set; }
public string FileName { get; set; }
public byte[] ImageData { get; set; }
public string File
{
get
{
string mimeType = "image/png";
string base64 = Convert.ToBase64String(ImageData);
return string.Format("data:{0},{1}", mimeType, base64);
}
}
}
Then add this line to the controller:
HttpPostedFileBase File = Request.Files[0];
Replace any IG.File entry with File for example:
if (File.ContentLength > (2 * 1024 * 1024))