public class Rpt { public string Title {set;get;} public int Price {set;get;} }
var list = new List<Rpt>(); list.Add(new Rpt{ Title = "عنوان دلخواه", Price = 1});
پس از ساخت لیست، از منبع داده StronglyTypedList استفاده کنید. یک مثال از این منبع داده
public class Rpt { public string Title {set;get;} public int Price {set;get;} }
var list = new List<Rpt>(); list.Add(new Rpt{ Title = "عنوان دلخواه", Price = 1});
namespace Decision.DomainClasses.Entities { /// <summary> /// انوع استعلام /// </summary> public class ResearchType:BaseEntity { /// <summary> /// نوع استعلام /// </summary> public int Title { get; set; } /// <summary> /// وضعیت نمایش /// </summary> public bool IsActive { get; set; } } }
public class MySettings { public string StringSetting { get; set; } public int IntSetting { get; set; }
public List<string> ListValues { get; } = new List<string>();
public ISet<string> Values { get; set; }
public ISet<string> Values { get; } = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
public static class ReportMethod { static FontSelector fontSelector = new FontSelector(); const char RightToLeftEmbedding = (char)PersianDate.RightToLeftEmbedding; const char PopDirectionalFormatting = (char)PersianDate.PopDirectionalFormatting; public static Dictionary<string, string> fontDicBody = new Dictionary<string, string> { { "BMitra", "B Mitra" }, { "tahoma", "tahoma" } }; public static Dictionary<string, string> fontDicHeader1 = new Dictionary<string, string> { { "BMitraBd", "B Mitra Bold" }, { "tahoma", "tahoma" } }; public static Dictionary<string, string> fontDicHeader2 = new Dictionary<string, string> { { "BTitrBd", "B Titr Bold" }, { "tahoma", "tahoma" } }; public static Dictionary<string, string> fontDicFooter = new Dictionary<string, string> { { "BMitra", "B Mitra" }, { "tahoma", "tahoma" } }; public static string FixWeakCharacters(string data) { if (string.IsNullOrWhiteSpace(data)) return string.Empty; var weakCharacters = new[] { @"\", "/", "+", "-", "=", ";", "$" }; foreach (var weakCharacter in weakCharacters) { data = data.Replace(weakCharacter, RightToLeftEmbedding + weakCharacter + PopDirectionalFormatting); } return data; } public static Phrase SetFont(string data, int fontType) { Dictionary<string, string> fontDic; float fontSize = 11; switch (fontType) { case 0: fontDic = fontDicBody; fontSize = 11; break; case 1: fontDic = fontDicHeader1; fontSize = 14; break; case 2: fontDic = fontDicFooter; fontSize = 12; break; case 11: fontDic = fontDicHeader2; fontSize = 18; break; default: fontDic = fontDicBody; fontSize = 11; break; } foreach (var item in fontDic) { FontFactory.Register("c:\\windows\\fonts\\" + item.Key + ".ttf"); Font newfont = FontFactory.GetFont(item.Value, BaseFont.IDENTITY_H, fontSize); if (newfont.Familyname != "unknown") fontSelector.AddFont(newfont); } return fontSelector.Process(FixWeakCharacters(data)); } public static PdfPCell SetCell(string text, int border, int colspan, int Horizontal, int Vertical, bool DirectionRTL, int fontType = 0) { if (DirectionRTL) { var cell = new PdfPCell { RunDirection = PdfWriter.RUN_DIRECTION_RTL }; cell.Border = border; cell.Colspan = colspan; cell.HorizontalAlignment = Horizontal; cell.VerticalAlignment = Vertical; cell.Phrase = new Phrase(ReportMethod.SetFont(text, fontType)); return cell; } else { var cell = new PdfPCell(); cell.Border = border; cell.Colspan = colspan; cell.HorizontalAlignment = Horizontal; cell.VerticalAlignment = Vertical; cell.Phrase = new Phrase(ReportMethod.SetFont(text, fontType)); return cell; } } }
public IPdfReportData CreatePdfReport_SRptTeach(int MemberID, List<sp_Teach_Communicate_Select_ReportTeachResult> Teach_Result, string st, List<sp_Institute_Center_Info_Select_Name_MasterResult> Info) { string fileName = string.Format("SRptTeach-{0}.pdf", Guid.NewGuid().ToString("N")); return new PdfReport() .DocumentPreferences(doc => { doc.RunDirection(PdfRunDirection.RightToLeft); doc.Orientation(PageOrientation.Landscape); doc.PageSize(PdfPageSize.A4); doc.DocumentMetadata(new DocumentMetadata { Author = Info[0].InstName, Application = "PdfRpt", Keywords = "گزارش", Subject = "گزارش ویژه", Title = "گزارش کارکرد مدرسید" }); doc.Compression(new CompressionSettings { EnableCompression = true, EnableFullCompression = true }); doc.PrintingPreferences(new PrintingPreferences { ShowPrintDialogAutomatically = false }); }) .DefaultFonts(fonts => { fonts.Path(System.IO.Path.Combine(Environment.GetEnvironmentVariable("SystemRoot"), "fonts\\" + ReportMethod.fontDicBody.ElementAt(0).Key + ".ttf"), System.IO.Path.Combine(Environment.GetEnvironmentVariable("SystemRoot"), "fonts\\" + ReportMethod.fontDicBody.ElementAt(1).Key + ".ttf")); fonts.Size(11); fonts.Color(System.Drawing.Color.Black); }) .PagesFooter(footer => { footer.CustomFooter(new CustomFooter(footer.PdfFont, PdfRunDirection.RightToLeft)); }) .PagesHeader(header => { header.CustomHeader(new CustomHeader_SRptTeach(MemberID, st, Info)); }) .MainTableTemplate(template => { //template.BasicTemplate(BasicTemplate.SimpleTemplate); template.CustomTemplate(new TransparentTemplate()); }) .MainTablePreferences(table => { table.ColumnsWidthsType(TableColumnWidthType.Relative); table.GroupsPreferences(new GroupsPreferences { GroupType = GroupType.IncludeGroupingColumns, RepeatHeaderRowPerGroup = true, ShowOneGroupPerPage = false, SpacingBeforeAllGroupsSummary = 5f, ShowGroupingPropertiesInAllRows = true }); }) .MainTableDataSource(dataSource => { dataSource.StronglyTypedList<sp_Teach_Communicate_Select_ReportTeachResult>(Teach_Result); }) .MainTableSummarySettings(summarySettings => { summarySettings.OverallSummarySettings("جمع مبالغ"); summarySettings.AllGroupsSummarySettings("جمع کل مبالغ"); }) .MainTableColumns(columns => { columns.AddColumn(column => { column.PropertyName<sp_Teach_Communicate_Select_ReportTeachResult>(x => x.RowNo); column.CellsHorizontalAlignment(HorizontalAlignment.Center); column.IsVisible(true); column.Order(0); column.Width(4); column.HeaderCell("ردیف"); }); columns.AddColumn(column => { column.PropertyName<sp_Teach_Communicate_Select_ReportTeachResult>(x => x.ParentName); column.CellsHorizontalAlignment(HorizontalAlignment.Center); column.IsVisible(true); column.Order(1); column.Width(5); column.HeaderCell("مرکز"); }); columns.AddColumn(column => { column.PropertyName<sp_Teach_Communicate_Select_ReportTeachResult>(x => x.FullName); column.CellsHorizontalAlignment(HorizontalAlignment.Center); column.IsVisible(true); column.Order(2); column.Width(12); column.HeaderCell("نام و نام خانوادگی"); column.Group(true, (val1, val2) => { return val1.ToString() == val2.ToString(); }); }); columns.AddColumn(column => { column.PropertyName<sp_Teach_Communicate_Select_ReportTeachResult>(x => x.TermInfoName); column.CellsHorizontalAlignment(HorizontalAlignment.Center); column.IsVisible(true); column.Order(3); column.Width(8); column.HeaderCell("ترم"); }); columns.AddColumn(column => { column.PropertyName<sp_Teach_Communicate_Select_ReportTeachResult>(x => x.Contract_NO); column.CellsHorizontalAlignment(HorizontalAlignment.Center); column.IsVisible(true); column.Order(4); column.Width(7); column.HeaderCell("شماره قرارداد"); }); columns.AddColumn(column => { column.PropertyName<sp_Teach_Communicate_Select_ReportTeachResult>(x => x.LessonFullCode); column.CellsHorizontalAlignment(HorizontalAlignment.Center); column.IsVisible(true); column.Order(5); column.Width(4); column.HeaderCell("کد درس"); }); columns.AddColumn(column => { column.PropertyName<sp_Teach_Communicate_Select_ReportTeachResult>(x => x.LessonName); column.CellsHorizontalAlignment(HorizontalAlignment.Center); column.IsVisible(true); column.Order(6); column.Width(10); column.HeaderCell("نام درس"); }); columns.AddColumn(column => { column.PropertyName<sp_Teach_Communicate_Select_ReportTeachResult>(x => x.Start_Date_Lesson); column.CellsHorizontalAlignment(HorizontalAlignment.Center); column.IsVisible(true); column.Order(7); column.Width(6); column.HeaderCell("تاریخ شروع"); }); columns.AddColumn(column => { column.PropertyName<sp_Teach_Communicate_Select_ReportTeachResult>(x => x.End_Date_Lesson); column.CellsHorizontalAlignment(HorizontalAlignment.Center); column.IsVisible(true); column.Order(8); column.Width(6); column.HeaderCell("تاریخ پایان"); }); columns.AddColumn(column => { column.PropertyName<sp_Teach_Communicate_Select_ReportTeachResult>(x => x.TeachAmount); column.CellsHorizontalAlignment(HorizontalAlignment.Center); column.IsVisible(true); column.Order(9); column.Width(6); column.HeaderCell("مبلغ حق التدریس(ریال)"); column.ColumnItemsTemplate(template => { template.TextBlock(); template.DisplayFormatFormula(obj => obj == null ? string.Empty : string.Format("{0:n0}", obj)); }); }); columns.AddColumn(column => { column.PropertyName<sp_Teach_Communicate_Select_ReportTeachResult>(x => x.DoTeacherTime); column.CellsHorizontalAlignment(HorizontalAlignment.Center); column.IsVisible(true); column.Order(10); column.Width(3); column.HeaderCell("ساعت کارکرد"); column.ColumnItemsTemplate(template => { template.TextBlock(); template.DisplayFormatFormula(obj => obj == null ? string.Empty : string.Format("{0:n0}", obj)); }); column.AggregateFunction(aggregateFunction => { aggregateFunction.NumericAggregateFunction(AggregateFunction.Sum); aggregateFunction.DisplayFormatFormula(obj => obj == null ? string.Empty : string.Format("{0:n0}", obj)); }); }); columns.AddColumn(column => { column.PropertyName("CanPay"); column.CalculatedField(true, list => { if (list == null) return string.Empty; var amount = list.GetSafeStringValueOf<sp_Teach_Communicate_Select_ReportTeachResult>(x => x.TeachAmount); var doTime = list.GetSafeStringValueOf<sp_Teach_Communicate_Select_ReportTeachResult>(x => x.DoTeacherTime); var result = float.Parse(amount) * float.Parse(doTime); return Convert.ToDecimal(result); }); column.CellsHorizontalAlignment(HorizontalAlignment.Center); column.IsVisible(true); column.Order(11); column.Width(7); column.HeaderCell("قابل پرداخت(ریال)"); column.ColumnItemsTemplate(template => { template.TextBlock(); template.DisplayFormatFormula(obj => obj == null ? string.Empty : string.Format("{0:n0}", obj)); }); column.AggregateFunction(aggregateFunction => { aggregateFunction.NumericAggregateFunction(AggregateFunction.Sum); aggregateFunction.DisplayFormatFormula(obj => obj == null ? string.Empty : string.Format("{0:n0}", obj)); }); }); columns.AddColumn(column => { column.PropertyName<sp_Teach_Communicate_Select_ReportTeachResult>(x => x.Personal_Education); column.CellsHorizontalAlignment(HorizontalAlignment.Center); column.IsVisible(true); column.Order(12); column.Width(6); column.HeaderCell("مدرک تحصیلی"); }); //columns.AddColumn(column => //{ // column.PropertyName("Descriptions"); // column.CalculatedField(true, // list => // { // if (list == null) // return string.Empty; // var Row = list.GetSafeStringValueOf<sp_Teach_Communicate_Select_ReportTeachResult>(x => x.RowNoPerson); // return ""; // }); // column.CellsHorizontalAlignment(HorizontalAlignment.Center); // column.IsVisible(true); // column.Order(13); // column.Width(3); // column.HeaderCell("توضیحات"); //}); }) .MainTableEvents(events => { events.DataSourceIsEmpty(message: "اطلاعاتی برای نمایش وجود ندارد."); events.DocumentClosing(docClose => { string[] msgField = { "مدیر گروه", Info.Where(sp => sp.ID == MemberID).FirstOrDefault().InstKindName, Info.Where(sp => sp.ID == 0).FirstOrDefault().InstKindName, "امور مالی", "معاون پشتیبانی" }; string[] dataField = { "", Info.Where(sp => sp.ID == MemberID).FirstOrDefault().MasterName, Info.Where(sp => sp.ID == 0).FirstOrDefault().MasterName, "", Info.Where(sp => sp.ID == 1).FirstOrDefault().MasterName }; var infoTable = new PdfGrid(msgField.Length) { RunDirection = PdfWriter.RUN_DIRECTION_RTL, WidthPercentage = 100 }; foreach (var item in msgField) { infoTable.AddCell(ReportMethod.SetCell(item, PdfPCell.NO_BORDER, 1, PdfPCell.ALIGN_CENTER, PdfPCell.ALIGN_MIDDLE, true)); } foreach (var item in dataField) { infoTable.AddCell(ReportMethod.SetCell(item, PdfPCell.NO_BORDER, 1, PdfPCell.ALIGN_CENTER, PdfPCell.ALIGN_MIDDLE, true)); } docClose.PdfDoc.Add(infoTable); }); }) .Export(export => { export.ToExcel(); export.ToCsv(); export.ToXml(); export.ToString(); }) .Generate(data => { fileName = HttpUtility.UrlEncode(fileName, Encoding.UTF8); data.FlushInBrowser(fileName, FlushType.Inline); }); //.Generate(data => data.AsPdfFile(string.Format("{0}\\PlansPage\\RptIListSample-{1}.pdf", AppPath.ApplicationPath, Guid.NewGuid().ToString("N")))); }
namespace Academy.Control.Reports { public class CustomHeader_SRptTeach : IPageHeader { public IPdfFont PdfRptFont { set; get; } string st; List<sp_Institute_Center_Info_Select_Name_MasterResult> Info; int MemberID; public CustomHeader_SRptTeach(int MemberID, string st, List<sp_Institute_Center_Info_Select_Name_MasterResult> Info) { this.st = st; this.Info = Info; this.MemberID = MemberID; } public PdfGrid RenderingGroupHeader(Document pdfDoc, PdfWriter pdfWriter, IList<CellData> rowdata, IList<SummaryCellData> summaryData) { // return null; var groupFullName = rowdata.GetSafeStringValueOf<sp_Teach_Communicate_Select_ReportTeachResult>(x => x.FullName); var groupPersonalEducation = rowdata.GetSafeStringValueOf<sp_Teach_Communicate_Select_ReportTeachResult>(x => x.Personal_Education); var table = new PdfGrid(2) { WidthPercentage = 100 }; table.AddSimpleRow( (cellData, cellProperties) => { cellData.Value = "نام و نام خانوادگی:"; cellProperties.PdfFont = PdfRptFont; cellProperties.PdfFontStyle = DocumentFontStyle.Bold; cellProperties.HorizontalAlignment = HorizontalAlignment.Left; }, (cellData, cellProperties) => { cellData.Value = groupFullName; cellProperties.PdfFont = PdfRptFont; cellProperties.HorizontalAlignment = HorizontalAlignment.Left; }); table.AddSimpleRow( (cellData, cellProperties) => { cellData.Value = "مدرک تحصیلی :"; cellProperties.PdfFont = PdfRptFont; cellProperties.PdfFontStyle = DocumentFontStyle.Bold; cellProperties.HorizontalAlignment = HorizontalAlignment.Left; }, (cellData, cellProperties) => { cellData.Value = groupPersonalEducation; cellProperties.PdfFont = PdfRptFont; cellProperties.HorizontalAlignment = HorizontalAlignment.Left; }); return table.AddBorderToTable(borderColor: BaseColor.LIGHT_GRAY, spacingBefore: 10f); } public PdfGrid RenderingReportHeader(Document pdfDoc, PdfWriter pdfWriter, IList<SummaryCellData> summaryData) { var tableMain = new PdfGrid(1) { RunDirection = PdfWriter.RUN_DIRECTION_RTL, WidthPercentage = 100 }; tableMain.DefaultCell.Border = PdfPCell.NO_BORDER; PdfGrid table = new PdfGrid(3); table.DefaultCell.Border = PdfPCell.NO_BORDER; table.AddCell(ReportMethod.SetCell("", PdfPCell.NO_BORDER, 1, PdfPCell.ALIGN_CENTER, PdfPCell.ALIGN_MIDDLE, false)); table.AddCell(ReportMethod.SetCell("گزارش کارکرد مدرسین ", PdfPCell.NO_BORDER, 1, PdfPCell.ALIGN_CENTER, PdfPCell.ALIGN_MIDDLE, true,11)); PdfPTable tbRight = new PdfPTable(1) { RunDirection = PdfWriter.RUN_DIRECTION_RTL }; tbRight.DefaultCell.Border = PdfPCell.NO_BORDER; Image _image = Image.GetInstance(System.IO.Path.Combine(AppPath.ApplicationPath, "Content\\Images\\p_jahad2.jpg")); var cellImg = new PdfPCell(_image, false) { Border = PdfPCell.NO_BORDER }; cellImg.HorizontalAlignment = PdfPCell.ALIGN_CENTER; tbRight.AddCell(cellImg); tbRight.AddCell(ReportMethod.SetCell(Info[0].InstName, PdfPCell.NO_BORDER, 1, PdfPCell.ALIGN_CENTER, PdfPCell.ALIGN_MIDDLE, false,1)); tbRight.AddCell(ReportMethod.SetCell(Info.Where(sp => sp.ID == MemberID).FirstOrDefault().SecondName, PdfPCell.NO_BORDER, 1, PdfPCell.ALIGN_CENTER, PdfPCell.ALIGN_MIDDLE, false,1)); table.AddCell(tbRight); PdfGrid tbLeft = new PdfGrid(2) { RunDirection = PdfWriter.RUN_DIRECTION_RTL }; tbLeft.DefaultCell.Border = PdfPCell.NO_BORDER; tbLeft.AddCell(ReportMethod.SetCell("تاریخ گزارش : " + System.DateTime.Now.ToPersianDateTime("/", false), PdfPCell.NO_BORDER, 2, PdfPCell.ALIGN_LEFT, PdfPCell.ALIGN_MIDDLE, false)); tbLeft.AddCell(ReportMethod.SetCell("از تاریخ " + st.Split(';')[0], PdfPCell.NO_BORDER, 1, PdfPCell.ALIGN_LEFT, PdfPCell.ALIGN_MIDDLE, false)); tbLeft.AddCell(ReportMethod.SetCell("تا تاریخ " + st.Split(';')[1], PdfPCell.NO_BORDER, 1, PdfPCell.ALIGN_LEFT, PdfPCell.ALIGN_MIDDLE, false)); table.AddCell(tbLeft); table.AddCell(ReportMethod.SetCell("", PdfPCell.NO_BORDER, 1, PdfPCell.ALIGN_CENTER, PdfPCell.ALIGN_MIDDLE, false)); table.AddCell(ReportMethod.SetCell("", PdfPCell.NO_BORDER, 1, PdfPCell.ALIGN_CENTER, PdfPCell.ALIGN_MIDDLE, false)); tableMain.AddCell(table); return tableMain; } } }
using System;
namespace MvcApplication8.Models
{
public class Employee
{
public int Id { set; get; }
public string Name { set; get; }
public decimal Salary { set; get; }
public string Address { set; get; }
public bool IsMale { set; get; }
public DateTime AddDate { set; get; }
}
}
using System;
using System.Web.Mvc;
using MvcApplication8.Models;
namespace MvcApplication8.Controllers
{
public class EmployeeController : Controller
{
public ActionResult Create()
{
var employee = new Employee { AddDate = DateTime.Now };
return View(employee);
}
}
}
@model MvcApplication8.Models.Employee
@{
ViewBag.Title = "Create";
}
<h2>Create An Employee</h2>
@using (Html.BeginForm(actionName: "Create", controllerName: "Employee"))
{
@Html.EditorForModel()
<input type="submit" value="Save" />
}
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
namespace MvcApplication8.Models
{
public class Employee
{
//[ScaffoldColumn(false)]
[HiddenInput(DisplayValue=false)]
public int Id { set; get; }
public string Name { set; get; }
[DisplayName("Annual Salary ($)")]
public decimal Salary { set; get; }
public string Address { set; get; }
[DisplayName("Is Male?")]
public bool IsMale { set; get; }
[DisplayName("Start Date")]
[DataType(DataType.Date)]
public DateTime AddDate { set; get; }
}
}
[DataType(DataType.MultilineText)]
[DisplayName("Gender")]
[UIHint("GenderOptions")]
public bool IsMale { set; get; }
@model bool
<p>@Html.RadioButton("", false, !Model) Female</p>
<p>@Html.RadioButton("", true, Model) Male</p>
@model Enum
@Html.DropDownListFor(m => m, Enum.GetValues(Model.GetType())
.Cast<Enum>()
.Select(m => {
string enumVal = Enum.GetName(Model.GetType(), m);
return new SelectListItem() {
Selected = (Model.ToString() == enumVal),
Text = enumVal,
Value = enumVal
};
}))
[UIHint("Enum")]
[DisplayFormat(NullDisplayText = "-")]
[DisplayFormat(DataFormatString = "{0:n}")]
[DisplayFormat(DataFormatString = "{0:n}", ApplyFormatInEditMode = true)]
using System;
using System.Collections.Generic;
namespace MvcApplication8.Models
{
public class Employees
{
public IList<Employee> CreateEmployees()
{
return new[]
{
new Employee { Id = 1, AddDate = DateTime.Now.AddYears(-3), Name = "Emp-01", Salary = 3000},
new Employee { Id = 2, AddDate = DateTime.Now.AddYears(-2), Name = "Emp-02", Salary = 2000},
new Employee { Id = 3, AddDate = DateTime.Now.AddYears(-1), Name = "Emp-03", Salary = 1000}
};
}
}
}
public ActionResult EmployeeList()
{
var list = new Employees().CreateEmployees();
return View(list);
}
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Salary)
</td>
<td>
@Html.DisplayFor(modelItem => item.Address)
</td>
<td>
@Html.DisplayFor(modelItem => item.IsMale)
</td>
<td>
@Html.DisplayFor(modelItem => item.AddDate)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id=item.Id }) |
@Html.ActionLink("Details", "Details", new { id=item.Id }) |
@Html.ActionLink("Delete", "Delete", new { id=item.Id })
</td>
</tr>
}
\Views\Employee\_EmployeeItem.cshtml
@model MvcApplication8.Models.Employee
<tr>
<td>
@Html.DisplayFor(x => x.Name)
</td>
<td>
@Html.DisplayFor(x => x.Salary)
</td>
<td>
@Html.DisplayFor(x => x.Address)
</td>
<td>
@Html.DisplayFor(x => x.IsMale)
</td>
<td>
@Html.DisplayFor(x => x.AddDate)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id = Model.Id }) |
@Html.ActionLink("Details", "Details", new { id = Model.Id }) |
@Html.ActionLink("Delete", "Delete", new { id = Model.Id })
</td>
</tr>
@foreach (var item in Model) {
@Html.Partial("_EmployeeItem", item)
}
using System.Web.Mvc;
namespace MvcApplication8.Controllers
{
public class MenuController : Controller
{
[ChildActionOnly]
public ActionResult ShowMenu(string options)
{
return PartialView(viewName: "_ShowMenu", model: options);
}
}
}
@model string
<ul>
<li>
@Model
</li>
</ul>
@Html.Action(actionName: "ShowMenu", controllerName: "Menu",
routeValues: new { options = "some data..." })
@{ Html.RenderAction("About"); }
And not @Html.RenderAction("About")
public class Person { //... public virtual IList<Center> PreferedCenters { get; set; } public virtual IList<Center> ActiveCenters { get; set; } public Person() { PreferedCenters = new List<Center>(); ActiveCenters = new List<Center>(); } }
public class Center { //... public virtual IList<Person> Persons { get; set; } public Center() { Persons = new List<Person>(); } }
An unhandled exception of type 'System.InvalidOperationException' occurred in EntityFramework.dll Additional information: Multiplicity constraint violated. The role 'Center_Persons_Source' of the relationship 'Yarigaran.DataLayer.Center_Persons' has multiplicity 1 or 0..1.
همه ما با DisplayAttribute در DataAnnotaion آشنا هستیم. چیزی شبیه زیر برای یک موجودیت:
public class Student{ [Display(Name="نام خانوادگی")] public string FamilyName { get; set;} }
با استفاده از tag helper ای به نام asp-for میتوان متادیتای Name را به کاربر، در سمت رابط کاربری نشان داد؛ برای مثال:
<label asp-for="FamilyName"></label>
و یا موقع اعتبارسنجی میتوان به جای نشان دادن نام FamilyName از نام مفهومتری مانند نام خانوادگی استفاده نمود.
چه خوب بود اگر میشد علاوه بر نام، توصیفی از فیلد نیز برای آن در این قسمت وجود داشته باشد؛ به عبارت دیگر اگر کد زیر را داشتیم:
[Display( Name = "نام خانوادگی", Description = "بهتر است فقط در اینجا نام خانوادگی شخص وارد شود")] public string FamilyName{ get; set; }
بتوان از tag helper ای مانند زیر استفاده نمود:
<span asp-description-for="FamilyName"></span>
که در نهایت چنین خروجی html ای داشته باشیم:
<span>بهتر است فقط در اینجا نام خانوادگی شخص وارد شود</span>
برای این منظور میتوان از کلاس زیر بهره برد:
using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Razor.TagHelpers; [HtmlTargetElement("div", Attributes = ForAttributeName)] [HtmlTargetElement("p", Attributes = ForAttributeName)] [HtmlTargetElement("span", Attributes = ForAttributeName)] public sealed class DescriptionForTagHelper : TagHelper { private const string ForAttributeName = "asp-description-for"; [HtmlAttributeName(ForAttributeName)] public ModelExpression For { get; set; } = default!; public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (output == null) { throw new ArgumentNullException(nameof(output)); } var description = For.Metadata.Description; if (description != null) { // Do not update the content if another tag helper // targeting this element has already done so. if (!output.IsContentModified) { var childContent = await output.GetChildContentAsync(); if (childContent.IsEmptyOrWhiteSpace) { output.Content.SetHtmlContent(description); } else { output.Content.SetHtmlContent(childContent); } } } } }
کلاس DescriptionForTagHelper از کلاس پایه TagHelper ارث بری نموده است و متد ProcessAsync آن به نحوی که asp-description-for را بپذیرد override شده است.
حوزه اعمال این tag helper به span، p و div محدود شده است؛ اما میتوان با گذاشتن یک ستاره (*) آن را به کل المانهای html اعمال کرد.
Request # 2: GET - 3,818 ms - <system> - 200 - /indexes/dynamic/Questions?&query=Title%3ARaven*&pageSize=128
using System; using System.Linq; using Raven.Client.Document; using RavenDBSample01.Models; using Raven.Client; using Raven.Client.Linq; using Raven.Client.Indexes; namespace RavenDBSample01 { class Program { static void Main(string[] args) { using (var store = new DocumentStore { Url = "http://localhost:8080" }.Initialize()) { store.DatabaseCommands.PutIndex( name: "Questions/ByTitle", indexDef: new IndexDefinitionBuilder<Question> { Map = questions => questions.Select(question => new { Title = question.Title } ) }); } } } }
public class QuestionsByTitle : AbstractIndexCreationTask<Question> { public QuestionsByTitle() { Map = questions => questions.Select(question => new { Title = question.Title }); } }
using (var store = new DocumentStore { Url = "http://localhost:8080" }.Initialize()) { IndexCreation.CreateIndexes(typeof(QuestionsByTitle).Assembly, store); }
using (var store = new DocumentStore { Url = "http://localhost:8080" }.Initialize()) { using (var session = store.OpenSession()) { var questions = session.Query<Question>(indexName: "QuestionsByTitle") .Where(x => x.Title.StartsWith("Raven")).Take(128); foreach (var question in questions) { Console.WriteLine(question.Title); } } }
Request # 147: GET - 58 ms - <system> - 200 - /indexes/QuestionsByTitle?&query=Title%3ARaven*&pageSize=128 Query: Title:Raven* Time: 7 ms Index: QuestionsByTitle Results: 2 returned out of 2 total.
var questions = session.Query<Question, QuestionsByTitle>() .Where(x => x.Title.StartsWith("Raven")).Take(128);
public class QuestionsCountByTitleReduceResult { public string Title { set; get; } public int Count { set; get; } } public class QuestionsCountByTitle : AbstractIndexCreationTask<Question, QuestionsCountByTitleReduceResult> { public QuestionsCountByTitle() { Map = questions => questions.Select(question => new { Title = question.Title, Count = 1 }); Reduce = results => results.GroupBy(x => x.Title) .Select(g => new { Title = g.Key, Count = g.Sum(x => x.Count) }); } }
using (var store = new DocumentStore { Url = "http://localhost:8080" }.Initialize()) { IndexCreation.CreateIndexes(typeof(QuestionsCountByTitle).Assembly, store); using (var session = store.OpenSession()) { var result = session.Query<QuestionsCountByTitleReduceResult, QuestionsCountByTitle>() .FirstOrDefault(x => x.Title == "Raven") ?? new QuestionsCountByTitleReduceResult(); Console.WriteLine(result.Count); } }
سناریویی را در نظر بگیرید که یک برنامه وب نوشته شده، قرار است به چندین مستاجر (مشتری یا tenant) خدماتی را ارائه کند. در این حالت اطلاعات هر مشتری به صورت کاملا جدا شده از دیگر مشتریان در سیستم قرار دارد و فقط به همان قسمتها دسترسی دارد.
مثلا یک برنامه مدیریت رستوران را در نظر بگیرید که برای هر مشتری، در دامین
مخصوص به خود قرار دارد و همه آنها به یک سیستم متمرکز متصل شده و اطلاعات
خود را از آنجا دریافت میکنند.
در معماری Multi-Tenancy، چندین کاربر میتوانند از یک نمونه (Single
Instance) از اپلیکیشن نرمافزاری استفاده کنند. یعنی این نمونه روی سرور
اجرا میشود و به چندین کاربر سرویس میدهد. هر کاربر را یک Tenant
مینامیم. میتوان به Tenantها امکان تغییر و شخصیسازی بخشی از اپلیکیشن
را داد؛ مثلا امکان تغییر رنگ رابط کاربری و یا قوانین کسبوکار، اما آنها نمیتوانند
کدهای اپلیکیشن را شخصیسازی کنند.
PM> Install-Package SaasKit.Multitenancy
public class AppTenant { public string Name { get; set; } public string[] Hostnames { get; set; } }
public class AppTenantResolver : ITenantResolver<AppTenant> { IEnumerable<AppTenant> tenants = new List<AppTenant>(new[] { new AppTenant { Name = "Tenant 1", Hostnames = new[] { "localhost:6000", "localhost:6001" } }, new AppTenant { Name = "Tenant 2", Hostnames = new[] { "localhost:6002" } } }); public async Task<TenantContext<AppTenant>> ResolveAsync(HttpContext context) { TenantContext<AppTenant> tenantContext = null; var tenant = tenants.FirstOrDefault(t => t.Hostnames.Any(h => h.Equals(context.Request.Host.Value.ToLower()))); if (tenant != null) { tenantContext = new TenantContext<AppTenant>(tenant); } return tenantContext; } }
public void ConfigureServices(IServiceCollection services) { services.AddMultitenancy<AppTenant, AppTenantResolver>(); }
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { // after .UseStaticFiles() app.UseMultitenancy<AppTenant>(); // before .UseMvc() }
public class HomeController : Controller { private AppTenant tenant; public HomeController(AppTenant tenant) { this.tenant = tenant; } }
@inject AppTenant Tenant;
<a asp-controller="Home" asp-action="Index">@Tenant.Name</a>
"commands": { "web": "Microsoft.AspNet.Server.Kestrel --server.urls=http://localhost:6000;http://localhost:6001;http://localhost:6002", },
dotnet run
از آنجائیکه نوشتن مشخصات مستاجرها در کد زیاد جالب نیست، برای همین
تصمیم داریم که این مشخصات را با استفاده از قابلیتهای ASP.NET Core از
فایل appsettings.json دریافت کنیم. تنظیمات مستاجرها را مطابق اطلاعات زیر به این فایل اضافه کنید:
"Multitenancy": { "Tenants": [ { "Name": "Tenant 1", "Hostnames": [ "localhost:6000", "localhost:6001" ] }, { "Name": "Tenant 2", "Hostnames": [ "localhost:6002" ] } ] }
public class MultitenancyOptions { public Collection<AppTenant> Tenants { get; set; } }
services.Configure<MultitenancyOptions>(Configuration.GetSection("Multitenancy"));
public class AppTenantResolver : ITenantResolver<AppTenant> { private readonly IEnumerable<AppTenant> tenants; public AppTenantResolver(IOptions<MultitenancyOptions> options) { this.tenants = options.Value.Tenants; } public async Task<TenantContext<AppTenant>> ResolveAsync(HttpContext context) { TenantContext<AppTenant> tenantContext = null; var tenant = tenants.FirstOrDefault(t => t.Hostnames.Any(h => h.Equals(context.Request.Host.Value.ToLower()))); if (tenant != null) { tenantContext = new TenantContext<AppTenant>(tenant); } return Task.FromResult(tenantContext); } }
اولین قدم در پیاده سازی یک معماری multi-tenant، تصمیم گیری درباره این
موضوع است که شما چطور مستاجر خود را شناسایی کنید. به محض این شناسایی شما میتوانید عملیاتهای بعدی خود را مثل تفکیک بخشی از برنامه، فیلتر کردن دادهای، نمایش یک view خاص برای هر مستاجر و یا بازنویسی قسمتهای مختلف
برنامه بر اساس هر مستاجر، انجام دهید.
_ سورس مثال بالا در گیت هاب قابل دریافت میباشد.
_ منبع: اینجا