ASP.NET核心创建Outlook日历提醒与创建操作方法

问题描述:

我使用ASP.NET 2.0的核心MVC,C#,代码的EntityFramework第一和SQL Server 2016ASP.NET核心创建Outlook日历提醒与创建操作方法

我有一个Web表单供用户填写。最终用户必须输入他们的名字和姓氏,从下拉列表中选择他们的部门,并从下拉列表中选择一个日期值。

一旦最终用户提交的他们的数据确认,显示的网页,他们输入和选择的值。是否有方法在确认页面上生成Outlook日历文件。因此,当他们点击该文件时,会根据他们从下拉列表中选择的日期添加日历提醒。

我会在必要时发布我的代码。

模型

public class Employee 
{ 
    public int EmployeeID { get; set; } 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 

    public int DepartmentID { get; set; } 
    public Department Department { get; set; } 

    public int AppointmentID { get; set; } 
    public Appointment Appointment { get; set; } 
} 

public class Department 
{ 
    public int DepartmentID { get; set; } 
    public string Name { get; set; } 

    public ICollection<Employee> Employees { get; set; } 
} 

public class Appointment 
{ 
    public int AppointmentID { get; set; } 
    public string TimeSlot { get; set; } 

    public ICollection<Employee> Employees { get; set; } 
} 

的DbContext

public class WinTenDbContext : DbContext 
{ 
    public WinTenDbContext(DbContextOptions<WinTenDbContext> options) : base(options) 
    { } 

    public DbSet<Employee> Employees { get; set; } 
    public DbSet<Department> Departments { get; set; } 
    public DbSet<Appointment> Appointments { get; set; } 

    protected override void OnModelCreating(ModelBuilder modelBuilder) 
    { 
     modelBuilder.Entity<Employee>() 
      .HasKey(e => e.EmployeeID); 

     modelBuilder.Entity<Employee>() 
      .Property(e => e.FirstName) 
      .HasColumnType("varchar(50)") 
      .HasMaxLength(50) 
      .IsRequired(); 

     modelBuilder.Entity<Employee>() 
      .Property(e => e.LastName) 
      .HasColumnType("varchar(50)") 
      .HasMaxLength(50) 
      .IsRequired(); 

     modelBuilder.Entity<Department>() 
      .HasKey(d => d.DepartmentID); 

     modelBuilder.Entity<Department>() 
      .Property(d => d.Name) 
      .HasColumnType("varchar(50)") 
      .HasMaxLength(50); 

     modelBuilder.Entity<Appointment>() 
      .HasKey(a => a.AppointmentID); 

     modelBuilder.Entity<Appointment>() 
      .Property(a => a.TimeSlot) 
      .HasColumnType("varchar(50)") 
      .HasMaxLength(50); 
    } 
} 

的ViewModels

public class EmployeeFormVM 
{ 
    public int EmployeeID { get; set; } 

    [Required(ErrorMessage = "Please enter your First Name")] 
    [Display(Name = "First Name")] 
    [StringLength(50)] 
    public string FirstName { get; set; } 

    [Required(ErrorMessage = "Please enter your Last Name")] 
    [Display(Name = "Last Name")] 
    [StringLength(50)] 
    public string LastName { get; set; } 

    [Required(ErrorMessage = "Please select your Department")] 
    [Display(Name = "Department")] 
    public int DepartmentID { get; set; } 

    public IEnumerable<Department> Departments { get; set; } 

    [Required(ErrorMessage = "Please select your Appointment")] 
    [Display(Name = "Appointment")] 
    public int AppointmentID { get; set; } 

    public IEnumerable<Appointment> Appointments { get; set; } 
} 

EmployeesController

public class EmployeesController : Controller 
{ 
    private readonly WinTenDbContext _context; 

    public EmployeesController(WinTenDbContext context) 
    { 
     _context = context; 
    } 

    public async Task<IActionResult> Index(string sortOrder, string currentFilter, string searchString, int? page) 
    { 
     ViewData["CurrentSort"] = sortOrder; 
     ViewData["FirstNameSortParm"] = sortOrder == "fname" ? "fname_desc" : "fname"; 
     ViewData["LastNameSortParm"] = String.IsNullOrEmpty(sortOrder) ? "lname_desc" : ""; 
     ViewData["DeptNameSortParm"] = sortOrder == "deptname" ? "deptname_desc" : "deptname"; 
     ViewData["DateSortParm"] = sortOrder == "time_slot" ? "time_slot_desc" : "time_slot"; 

     if (searchString != null) 
     { 
      page = 1; 
     } 
     else 
     { 
      searchString = currentFilter; 
     } 

     ViewData["CurrentFilter"] = searchString; 

     var employees = from s in _context.Employees.Include(e => e.Appointment).Include(e => e.Department) 
         select s; 

     if (!String.IsNullOrEmpty(searchString)) 
     { 
      employees = employees.Where(s => s.LastName.Contains(searchString) 
            || s.FirstName.Contains(searchString)); 
     } 

     switch (sortOrder) 
     { 
      case "fname": 
       employees = employees.OrderBy(s => s.FirstName); 
       break; 
      case "fname_desc": 
       employees = employees.OrderByDescending(s => s.FirstName); 
       break; 
      case "lname_desc": 
       employees = employees.OrderByDescending(s => s.LastName); 
       break; 
      case "deptname": 
       employees = employees.OrderBy(s => s.Department.Name); 
       break; 
      case "deptname_desc": 
       employees = employees.OrderByDescending(s => s.Department.Name); 
       break; 
      case "time_slot": 
       employees = employees.OrderBy(s => s.Appointment.AppointmentID); 
       break; 
      case "time_slot_desc": 
       employees = employees.OrderByDescending(s => s.Appointment.AppointmentID); 
       break; 
      default: 
       employees = employees.OrderBy(s => s.LastName); 
       break; 
     } 

     int pageSize = 10; 
     return View(await PaginatedList<Employee>.CreateAsync(employees.AsNoTracking(), page ?? 1, pageSize)); 
    } 

    // GET: Employees/Details/5 
    public async Task<IActionResult> Details(int? id) 
    { 
     if (id == null) 
     { 
      return NotFound(); 
     } 

     var employee = await _context.Employees 
      .Include(e => e.Appointment) 
      .Include(e => e.Department) 
      .SingleOrDefaultAsync(m => m.EmployeeID == id); 
     if (employee == null) 
     { 
      return NotFound(); 
     } 

     return View(employee); 
    } 

    // GET: Employees/Confirmation/5 
    public async Task<IActionResult> Confirmation(int? id) 
    { 
     if (id == null) 
     { 
      return NotFound(); 
     } 

     var employee = await _context.Employees.Include(d => d.Department).Include(a => a.Appointment) 
      .SingleOrDefaultAsync(m => m.EmployeeID == id); 

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

     return View(employee); 
    } 

    // GET: Employees/Create 
    public IActionResult Create() 
    { 
     var departments = _context.Departments.ToList(); 
     var appointments = _context.Appointments.Include(x => x.Employees).Where(x => !x.Em‌​ployees.Any()).ToLis‌​t(); 

     var viewModel = new EmployeeFormVM 
     { 
      Departments = departments, 
      Appointments = appointments 
     }; 

     return View(viewModel); 
    } 

    [HttpPost] 
    [ValidateAntiForgeryToken] 
    public async Task<IActionResult> Create(EmployeeFormVM employee) 
    { 
     if (ModelState.IsValid) 
     { 
      var emp = new Employee(); 
      { 
       emp.FirstName = employee.FirstName; 
       emp.LastName = employee.LastName; 
       emp.DepartmentID = employee.DepartmentID; 
       emp.AppointmentID = employee.AppointmentID; 
      } 

      // Query DB to check if Employee exists with same First/Last Name 
      Employee existingEmployee = await _context.Employees.SingleOrDefaultAsync(m => m.FirstName == employee.FirstName && m.LastName == employee.LastName); 
      if (existingEmployee != null) 
      { 
       // Display Error if duplicate employee 
       ModelState.AddModelError(string.Empty, "An employee with this name has already registered. Please contact the Service Desk for any scheduling conflicts."); 
       employee.Departments = _context.Departments.ToList(); 
       //employee.Appointments = _context.Appointments.ToList(); 
       employee.Appointments = _context.Appointments.ToList(); 
       return View(employee); 
      } 

      // Query DB to check if appointment has already been assigned to an employee 
      Employee existingAppointment = await _context.Employees.SingleOrDefaultAsync(m => m.AppointmentID == employee.AppointmentID); 
      if (existingAppointment != null) 
      { 
       // Display error if the appointment was already chosen 
       ModelState.AddModelError(string.Empty, "This appointment has already been taken. Please select another timeslot."); 
       employee.Departments = _context.Departments.ToList(); 
       //employee.Appointments = _context.Appointments.ToList(); 
       employee.Appointments = _context.Appointments.ToList(); 
       return View(employee); 
      } 

      _context.Add(emp); 
      await _context.SaveChangesAsync(); 
      //return RedirectToAction(nameof(Index)); 

      var newlyCreatedId = emp.EmployeeID; 
      return RedirectToAction(nameof(Confirmation), new { id = newlyCreatedId }); 
     } 
     return View(employee); 
    } 

    // GET: Employees/Edit/5 
    public async Task<IActionResult> Edit(int? id) 
    { 
     if (id == null) 
     { 
      return NotFound(); 
     } 

     var employeevm = new EmployeeFormVM(); 
     { 
      Employee employee = await _context.Employees.SingleOrDefaultAsync(m => m.EmployeeID == id); 

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

      employeevm.EmployeeID = employee.EmployeeID; 
      employeevm.FirstName = employee.FirstName; 
      employeevm.LastName = employee.LastName; 

      // Retrieve list of Departments 
      var departments = _context.Departments.ToList(); 
      employeevm.Departments = departments; 
      // Set the selected department 
      employeevm.DepartmentID = employee.DepartmentID; 

      // Retrieve list of Appointments 
      var appointments = _context.Appointments.ToList(); 
      employeevm.Appointments = appointments; 
      // Set the selected department 
      employeevm.AppointmentID = employee.AppointmentID; 
     } 
     return View(employeevm); 
    } 

    // POST: Employees/Edit/5 
    // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
    // more details see http://go.microsoft.com/fwlink/?LinkId=317598. 
    [HttpPost] 
    [ValidateAntiForgeryToken] 
    public async Task<IActionResult> Edit(EmployeeFormVM vmEdit) 
    { 
     if (ModelState.IsValid) 
     { 
      Employee employee = _context.Employees.SingleOrDefault(e => e.EmployeeID == vmEdit.EmployeeID); 

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

      employee.FirstName = vmEdit.FirstName; 
      employee.LastName = vmEdit.LastName; 
      employee.DepartmentID = vmEdit.DepartmentID; 
      employee.AppointmentID = vmEdit.AppointmentID; 

      try 
      { 
       _context.Update(employee); 
       await _context.SaveChangesAsync(); 
      } 
      catch (DbUpdateConcurrencyException) 
      { 
       if (!EmployeeExists(vmEdit.EmployeeID)) 
       { 
        return NotFound(); 
       } 
       else 
       { 
        throw; 
       } 
      } 
      return RedirectToAction(nameof(Index)); 
     } 
     return View(vmEdit); 
    } 

    // GET: Employees/Delete/5 
    public async Task<IActionResult> Delete(int? id) 
    { 
     if (id == null) 
     { 
      return NotFound(); 
     } 

     var employee = await _context.Employees 
      .Include(e => e.Appointment) 
      .Include(e => e.Department) 
      .SingleOrDefaultAsync(m => m.EmployeeID == id); 
     if (employee == null) 
     { 
      return NotFound(); 
     } 

     return View(employee); 
    } 

    // POST: Employees/Delete/5 
    [HttpPost, ActionName("Delete")] 
    [ValidateAntiForgeryToken] 
    public async Task<IActionResult> DeleteConfirmed(int id) 
    { 
     var employee = await _context.Employees.SingleOrDefaultAsync(m => m.EmployeeID == id); 
     _context.Employees.Remove(employee); 
     await _context.SaveChangesAsync(); 
     return RedirectToAction(nameof(Index)); 
    } 

    private bool EmployeeExists(int id) 
    { 
     return _context.Employees.Any(e => e.EmployeeID == id); 
    } 
} 

创建视图

@using (Html.BeginForm("Create", "Employees")) 
    { 
     @Html.ValidationSummary(true, "", new { @class = "validation-summary-errors" }) 

     <div class="form-group"> 
      @Html.LabelFor(e => e.FirstName) 
      @Html.TextBoxFor(e => e.FirstName, new { @class = "form-control" }) 
      @Html.ValidationMessageFor(e => e.FirstName) 
     </div> 

     <div class="form-group"> 
      @Html.LabelFor(e => e.LastName) 
      @Html.TextBoxFor(e => e.LastName, new { @class = "form-control" }) 
      @Html.ValidationMessageFor(e => e.LastName) 
     </div> 

     <div class="form-group"> 
      @Html.LabelFor(d => d.DepartmentID) 
      @Html.DropDownListFor(d => d.DepartmentID, new SelectList(Model.Departments, "DepartmentID", "Name"), "", new { @class = "form-control" }) 
      @Html.ValidationMessageFor(d => d.DepartmentID) 
     </div> 

     <div class="form-group"> 
      @Html.LabelFor(a => a.AppointmentID) 
      @Html.DropDownListFor(a => a.AppointmentID, new SelectList(Model.Appointments, "AppointmentID", "TimeSlot"), "", new { @class = "form-control" }) 
      @Html.ValidationMessageFor(a => a.AppointmentID) 
     </div> 

     <div class="form-group"> 
      <button type="submit" class="btn btn-primary">Submit</button> 
     </div> 
    } 

确认浏览

<div class="row"> 
<div class="col-md-12"> 
    <img src="~/images/confirm.png" /> 
    <h2>Thank you @Html.DisplayFor(model => model.FirstName) @Html.DisplayFor(model => model.LastName)!</h2>  
    <p>Your <b>@Html.DisplayFor(model => model.Appointment.TimeSlot)</b> appointment has been booked. If you need to reschedule this appointment, please call the Service Desk at x1380.</p> 
</div> 

首先,你需要能够gE的作用整理一个* .ics文件。它将是一个简单的文本文件,带有iCal标签。有诸如ical.NET等库可用于生成此文本,但您可以轻松使用StringBuilder。最终结果如下所示:

BEGIN:VCALENDAR 
VERSION:2.0 
PRODID:-//ZContent.net//Zap Calendar 1.0//EN 
CALSCALE:GREGORIAN 
METHOD:PUBLISH 
BEGIN:VEVENT 
SUMMARY:Abraham Lincoln 
UID:[email protected] 
SEQUENCE:0 
STATUS:CONFIRMED 
TRANSP:TRANSPARENT 
RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=2;BYMONTHDAY=12 
DTSTART:20080212 
DTEND:20080213 
DTSTAMP:20150421T141403 
CATEGORIES:U.S. Presidents,Civil War People 
LOCATION:Hodgenville\, Kentucky 
GEO:37.5739497;-85.7399606 
DESCRIPTION:Born February 12\, 1809\nSixteenth President (1861-1865)\n\n\n 
\nhttp://AmericanHistoryCalendar.com 
URL:http://americanhistorycalendar.com/peoplecalendar/1,328-abraham-lincol 
n 
END:VEVENT 
END:VCALENDAR 

正如您所看到的那样,生成此代码很容易,只需在适当的位置填写特定的事件信息即可。此格式基于RFC 5545,因此如果您需要更多信息,请详细阅读说明书。

但是你生成这个,你的行动,那么只会采取的事件ID,或什么的,生成的iCal格式的文本,然后返回它的结果:

public IActionResult CreateICal(int eventId) 
{ 
    var evt = db.Events.Find(eventId); 

    // generate iCal from event instancce 

    var bytes = Encoding.UTF8.GetBytes(icalText); 
    return File(bytes, "text/calendar", $"{evt.Name}.ics"); 
} 

然后,您的确认页上,您只需使用适当的事件ID和/或需要传递给操作来创建iCal的任何其他信息来创建指向此操作的链接。

+0

谢谢你回复这篇文章。你提供的Action方法,我假设eventId应该是我的情况下的EmployeeID?是否有需要添加到我的项目的命名空间?此外,日期的值全部列在用户选择的下拉列表中。价值被列为** 2017年11月8日 - Morning Slot 2 **。所以,我不确定如何根据这些数据制作日历活动。 2017年11月8日可能会工作,但不知道如何显示其他如早上槽2 – BoardmanBound

+0

这只是一个简单的例子来说明这一点。无论您需要创建iCal数据的任何数据,您都会转到此操作。然后,您可以直接使用传入的数据,也可以从某个数据存储中查找内容,然后使用该数据构建iCal。 –

+0

好吧,我会玩弄你提供的东西,看看我是否可以弄明白。当用户提交他/她的数据时,它会直接进入确认页面,显示他们输入的值,并从下拉列表中选择。您能否告诉我如何在调用日历操作方法的确认视图上对链接进行格式化? – BoardmanBound