DayPilot - returning a new View on EventClick - c#

I am currently attempting to implement DayPilot Lite MVC on my project. I've set up my events and they are clickable(tested with a Debug statement). However what i am looking to do is process the click and load a new View, using a ViewModel built from the id of the event I clicked.
public ActionResult Booking()
{
ApplicationDbContext db = new ApplicationDbContext();
int id = Dpc.eventID;
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Lesson lesson = db.Lessons.Find(id);
if (lesson == null)
{
return HttpNotFound();
}
return View(lesson);
}
class Dpc : DayPilotCalendar
{
public int eventID;
protected override void OnInit(InitArgs e)
{
ApplicationDbContext db = new ApplicationDbContext();
Events = from ev in db.Lessons select ev;
DataIdField = "ClassID";
DataTextField = "ClassLevel";
DataStartField = "ClassStartDate";
DataEndField = "ClassEndDate";
Update();
}
protected override void OnEventClick(EventClickArgs e)
{
//Test to check the method was firing
Debug.WriteLine("Hey I clicked you");
//Parse the event ID for processing
eventID = int.Parse(e.Id);
//Redirect to the booking page
Redirect("Schedule/Booking");
}
}
When I tried to code the Booking method, it resulted in telling me that Dpc.eventID needs an object reference. I have tried making the class and the variable public, but the error persists. I can't make the eventClick public as then i can't override the original. I'm using Redirect because if i try any other link it fails for the same reason. I'm guessing it's because it's a non-inherited subclass, but should i not still be able to access its member attributes if they have a public scope?

Related

How to call Delete Web API from C# code with Attribute Routing Enabled

I have a variety of APIs set up in my project, and most of them are working at this point. However, I'm struggling to get the DELETE API working on a button click in my .aspx page.
I have this code for the DELETE api, including my attribute route that I created:
public class ReviewController : ApiController
{
private ReviewAPIModel db = new ReviewAPIModel();
[Route("api/Review/delete/{id}")]
[HttpDelete]
[ResponseType(typeof(review))]
public IHttpActionResult Deletereview(int id)
{
review review = db.review.Find(id);
if (review == null)
{
return NotFound();
}
db.review.Remove(review);
db.SaveChanges();
return Ok(review);
}
}
I am sure that my attribute routing is enabled correctly.
I have this code for my button click:
protected void repReviews_ItemCommand(object source, RepeaterCommandEventArgs e)
{
if (e.CommandName == "Delete")
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:#####/api/review/delete");
var deleteTask = client.DeleteAsync(Convert.ToString(e.CommandArgument));
deleteTask.Wait();
var result = deleteTask.Result;
if (result.IsSuccessStatusCode)
{
Response.Redirect("MyReviews.aspx");
}
Response.Redirect("MyReviews.aspx");
}
}
}
When I try to run the code by clicking the button, it runs through it all (I checked by using breakpoints). However, the record is not deleted from the database, and is still on the screen.
All of the guidance that I've found for this kind of scenario is either A) using a SQL Data Source, or B) not using Attribute Routing (with A) being the primary issue with finding a helpful Google result).
How do I make these two things mesh together?
ETA: DB Context:
public partial class ReviewAPIModel : DbContext
{
public ReviewAPIModel()
: base("name=ReviewAPIModel")
{
}
public virtual DbSet<review> review { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
}
}
From the comments it would seem that the problem is not that the database is not removing the item. It is that the request's HTTP Verb (Delete) is not being accepted by the web server (HTTP 405 Method Not Allowed), even though you have the [HttpDelete] attribute on the action.
My suggestion would be to include the [AcceptVerbs] attribute on the action.
[Route("api/Review/delete/{id:int}")]
[HttpDelete]
[AcceptVerbs("DELETE")] //<-- ADD THIS
[ResponseType(typeof(review))]
public IHttpActionResult Deletereview(int id) {
review review = db.review.Find(id);
if (review == null) {
return NotFound();
}
db.review.Remove(review);
db.SaveChanges();
return Ok(review);
}

Where should i store my temporary view model in asp.net MVC?

I have created a page where users can select an answer from random questions.
The controller contains
public class TestController : Controller
{
private DBDataContext _context;
private HomeViewModel _model;
public TestController()
{
_context = new DBDataContext();
_model = new HomeViewModel();
}
// GET: Test
[Route("test-online")]
public ActionResult Index()
{
_model = new HomeViewModel()
{
Categories = _context.Categories.Select(x => x.ToCategories()).ToList(),
QuestionModel = new List<QuestionModel>()
};
ViewData.Model = _model;
return View(_model);
}
[HttpPost]
public void Go(Test t)
{
_model = (HomeViewModel)ViewData.Model;
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (_context != null)
{
_context.Dispose();
_context = null;
}
}
base.Dispose(disposing);
}
}
And the problem is where should i store my _model?
When a user selects an answer an ajax post is performed onto the Go method,
but unfortunately the ViewData.Model is now null
How can i fix this issue?
I tried both with ViewBag and ViewData since i do not want to use a public static property.
If you are saving your model temporarily to use it in another method, you should use TempData instead.
Instead of ViewData in Index method, use TempData. Ex :
TempData["myModel"] = _model;
You can retrieve the same in your Go method by using
_model = TempData["myModel"];
Please remember that TempData will hold the data for only one request. If you want data to persist for more than one request , you need to use TempData.peek and TempData.keep. You can find what it is from the below link
https://hassantariqblog.wordpress.com/2016/09/02/mvc-when-to-use-keep-vs-peek-in-asp-net-mvc/
You can keep your model via Session like following code.
// part where you set the model and session
var _model = new HomeViewModel()
{
Categories = _context.Categories.Select(x => x.ToCategories()).ToList(),
QuestionModel = new List<QuestionModel>()
};
Session["model"] = _model;
// part where you get the model and session
HomeViewModel model = null;
if(Session["model"] != null)
{
model = Session["model"] as HomeViewModel;
// your code here
}
What can be done for application pool reset case to dont lose Session data?
Session state works inProc mode which stores session state in memory on the Web server as a default, to dont lose session variables in case of application pool reset you can change state mode to StateServer or SQLServer which provides a solution to make session state preserved when the Web application is restarted.
Detail reference : https://msdn.microsoft.com/en-us/library/ms178586(v=vs.140).aspx

Xamarin Forms MVVM Clear Navigation Stack from INavigationService

The project I am working on contains the following structure:
When app is launched, user sees a Welcome page. At that point user has two options. They can either login or register. If logged in == true; then go to master detail page. Or in registration, if register == success then go to login page and follow the same process and end up in the master detail page.
-> Login Page ||
Welcome Page >> ================== || => MasterDetailPage
-> Register Page -> Login page ||
I am using MVVM Light to handle my navigation stack via INavigationService as my UI and business logic is separated via MVVM. Everything works pretty good except for I need to reset the navigation stack so the user will not be able to access any page before the "MasterDetailPage" showed above. Right now users can go back to login or registration or whatever page they were before, by using the hardware back button on Android or swiping from the left edge on iOS. Plus, There is a navigation back button on top navigation bar anyway.
My App.cs looks something like this
public App()
{
var nav = RegisterNavigationService();
SimpleIoc.Default.Register<INavigationService>(() => nav);
InitializeComponent();
var initialPage = new NavigationPage(new WelcomePage());
nav.Initialize(initialPage);
MainPage = initialPage;
}
private NavigationService RegisterNavigationService()
{
var nav = new NavigationService();
nav.Configure(Locator.LoginForm, typeof(LoginForm));
nav.Configure(Locator.RegisterSuccessPage, typeof(RegisterSuccessPage));
nav.Configure(Locator.RegistrationForm, typeof(RegistrationForm));
nav.Configure(Locator.WelcomePage, typeof(WelcomePage));
nav.Configure(Locator.MasterMainPage, typeof(MasterMainPage));
return nav;
}
On my view models, I handle the navigation commands like this:
public class LoginFormViewModel : BaseViewModel
{
private readonly INavigationService _navigationService;
public Command NavigateToMainPage { get; }
public LoginFormViewModel(INavigationService navigationService)
{
_navigationService = navigationService ?? throw new ArgumentNullException("navigationService");
NavigateToMainPage = new Command(() => NavigateToMainApp());
}
private void NavigateToMainApp()
{
_navigationService.NavigateTo(Locator.MasterMainPage);
}
}
Finally, my NavigationService.cs looks like this... I barely touched this part of the code... The only thing I tried is the 'ClearNavigationStack' method but that was a failure.
public class NavigationService : INavigationService, INavigationServiceExtensions
{
private Dictionary<string, Type> _pagesByKey = new Dictionary<string, Type>();
private NavigationPage _navigation;
public string CurrentPageKey
{
get
{
lock (_pagesByKey)
{
if (_navigation.CurrentPage == null)
{
return null;
}
var pageType = _navigation.CurrentPage.GetType();
return _pagesByKey.ContainsValue(pageType)
? _pagesByKey.First(p => p.Value == pageType).Key
: null;
}
}
}
public void GoBack()
{
_navigation.PopAsync();
}
public void NavigateTo(string pageKey)
{
NavigateTo(pageKey, null);
}
public void NavigateTo(string pageKey, object parameter)
{
lock (_pagesByKey)
{
if (_pagesByKey.ContainsKey(pageKey))
{
ConstructorInfo constructor;
object[] parameters;
var type = _pagesByKey[pageKey];
if (parameter == null)
{
constructor = type.GetTypeInfo()
.DeclaredConstructors
.FirstOrDefault(c => !c.GetParameters().Any());
parameters = new object[] { };
}
else
{
constructor = type.GetTypeInfo()
.DeclaredConstructors
.FirstOrDefault(
c =>
{
var p = c.GetParameters();
return p.Count() == 1
&& p[0].ParameterType == parameter.GetType();
});
parameters = new[] { parameter };
}
if (constructor == null)
{
throw new InvalidOperationException("No suitable constructor found for page " + pageKey);
}
var page = constructor.Invoke(parameters) as Page;
_navigation.PushAsync(page);
}
else
{
throw new ArgumentException(
string.Format("No such page: {0}. Did you forget to call NavigationService.Configure?", pageKey), "pageKey");
}
}
}
public void Configure(string pageKey, Type pageType)
{
lock (_pagesByKey)
{
if (_pagesByKey.ContainsKey(pageKey))
{
_pagesByKey[pageKey] = pageType;
}
else
{
_pagesByKey.Add(pageKey, pageType);
}
}
}
public void ClearNavigationStack()
{
lock (_pagesByKey)
{
foreach (var pageKey in _pagesByKey.Keys)
{
_pagesByKey.Remove(pageKey);
}
}
}
public void Initialize(NavigationPage navigation)
{
_navigation = navigation;
}
}
I've taken this bit from the following git repo: https://github.com/mallibone/MvvmLightNavigation.XamarinForms
by following this tutorial:
https://mallibone.com/post/xamarin.forms-navigation-with-mvvm-light
Note: It is a PCL.
Any suggestion is welcome as I've been on this for the last 2 days.
EDIT: Just now, I've managed to "hide" the nav stack by setting my MainPage to something like this
App.Current.MainPage = new MasterMainPage();
But it seems like a code smell and looks like a horrific hack. Plus I am not too sure if it "violates" the concepts I am following... And I guess this navigation stack will never be gone anyway as I will do other navigation stacks inside the master detail pages.
From your picture I see that you have Master/Detaied page inside Navigation page. Xamarin doesn't recommend to do that. I don't know how you are going to do it in MVVM Light but in regular Forms you have couple options to achieve what you want:
If you ever need to go back to your Login or register page you should use
await Navigation.PushModalAsync(new YourMasterDetailPage());
Then you can popmodal to get back to them BUT in this case Hardware button will still bring you to Login. You can use part of method 2 to clear stack after you navigated to you master-detail page but be careful - you cannot remove a page from stack if it is root and currently displayed page, so you will need to clear regular navigation stack only after login page is not displayed.
I wouldn't recommend that option as "Modal views are often temporary and brought on screen only long enough for the user to complete a task."
http://blog.adamkemp.com/2014/09/navigation-in-xamarinforms_2.html
If you don't need to go back you can use the follow to clear Navigation stack, it will also remove Back button
await Navigation.PushAsync(new YourMasterPage());
var pages = Navigation.NavigationStack.ToList();
foreach (var page in pages)
{
if (page.GetType() != typeof(YourMasterPage))
Navigation.RemovePage(page);
}

Am I using and disposing Entity Framework's Object Context (per request) correctly?

I have a web application where I have just began to use Entity Framework. I read the beginners tutorials, and topics about benefits of object context per request for web apps.
However, I am not sure my context is at the right place...
I found this very useful post (Entity Framework Object Context per request in ASP.NET?) and used the suggested code :
public static class DbContextManager
{
public static MyEntities Current
{
get
{
var key = "MyDb_" + HttpContext.Current.GetHashCode().ToString("x")
+ Thread.CurrentContext.ContextID.ToString();
var context = HttpContext.Current.Items[key] as MyEntities;
if (context == null)
{
context = new MyEntities();
HttpContext.Current.Items[key] = context;
}
return context;
}
}
}
And in Global.asax :
protected virtual void Application_EndRequest()
{
var key = "MyDb_" + HttpContext.Current.GetHashCode().ToString("x")
+ Thread.CurrentContext.ContextID.ToString();
var context = HttpContext.Current.Items[key] as MyEntities;
if (context != null)
{
context.Dispose();
}
}
Then, I am using it in my pages :
public partial class Login : System.Web.UI.Page
{
private MyEntities context;
private User user;
protected void Page_Load(object sender, EventArgs e)
{
context = DbContextManager.Current;
if (Membership.GetUser() != null)
{
Guid guid = (Guid)Membership.GetUser().ProviderUserKey;
user = context.Users.Single(u => (u.Id == guid));
}
}
protected void _Button_Click(object sender, EventArgs e)
{
Item item = context.Items.Single(i => i.UserId == user.Id);
item.SomeFunctionThatUpdatesProperties();
context.SaveChanges();
}
}
I did read a lot but this is still a little bit confused for me.
Is the context getter okay in Page_Load ? Do I still need to use "using" or will disposal be okay with the Global.asax method ?
If I am confusing something I am sorry and I would be really, really grateful if someone could help me understand where it should be.
Thanks a lot !
Edits following nativehr answer and comments :
Here is the DbContextManager:
public static class DbContextManager
{
public static MyEntities Current
{
get
{
var key = "MyDb_" + typeof(MyEntities).ToString();
var context = HttpContext.Current.Items[key] as MyEntities;
if (context == null)
{
context = new MyEntities();
HttpContext.Current.Items[key] = context;
}
return context;
}
}
}
The page :
public partial class Login : System.Web.UI.Page
{
private User user;
protected void Page_Load(object sender, EventArgs e)
{
if (Membership.GetUser() != null)
{
Guid guid = (Guid)Membership.GetUser().ProviderUserKey;
user = UserService.Get(guid);
}
}
protected void _Button_Click(object sender, EventArgs e)
{
if (user != null)
{
Item item = ItemService.GetByUser(user.Id)
item.SomeFunctionThatUpdatesProperties();
ItemService.Save(item);
}
}
}
And the ItemService class :
public static class ItemService
{
public static Item GetByUser(Guid userId)
{
using (MyEntities context = DbContextManager.Current)
{
return context.Items.Single(i => (i.UserId == userId));
}
}
public static void Save(Item item)
{
using (MyEntities context = DbContextManager.Current)
{
context.SaveChanges();
}
}
}
I would not rely on Thread.CurrentContext property.
Firstly, Microsoft says, Context class is not intended to be used directly from your code:
https://msdn.microsoft.com/en-us/library/system.runtime.remoting.contexts.context%28v=vs.110%29.aspx
Secondly, imagine you want to make an async call to the database.
In this case an additional MyEntities instance will be constructed, and it will not be disposed in Application_EndRequest.
Furthermore, ASP.NET itself does not guarantee not to switch threads while executing a request.
I had a similar question, have a look at this:
is thread switching possible during request processing?
I would use "MyDb_" + typeof(MyEntities).ToString() instead.
Disposing db context in Application_EndRequest is OK, but it produces a bit performance hit, 'cause your context will stay not disposed longer than needed, it is better to close it as soon as possible (you actually don't need an open context to render the page, right?)
Context pre request implementation would make sense if it has to be shared between different parts of your code, insted of creating a new instance each time.
For example, if you utilize the Repository pattern, and several repositories share the same db context while executing a request.
Finally you call SaveChanges and all the changes made by different repositories are committed in a single transaction.
But in your example you are calling the database directly from your page's code, in this case I don't see any reason to not create a context directly with using.
Hope this helps.
Update: a sample with Context per request:
//Unit of works acts like a wrapper around DbContext
//Current unit of work is stored in the HttpContext
//HttpContext.Current calls are kept in one place, insted of calling it many times
public class UnitOfWork : IDisposable
{
private const string _httpContextKey = "_unitOfWork";
private MyContext _dbContext;
public static UnitOfWork Current
{
get { return (UnitOfWork) HttpContext.Current.Items[_httpContextKey]; }
}
public UnitOfWork()
{
HttpContext.Current.Items[_httpContextKey] = this;
}
public MyEntities GetContext()
{
if(_dbContext == null)
_dbContext = new MyEntities();
return _dbContext;
}
public int Commit()
{
return _dbContext != null ? _dbContext.SaveChanges() : null;
}
public void Dispose()
{
if(_dbContext != null)
_dbContext.Dispose();
}
}
//ContextManager allows repositories to get an instance of DbContext
//This implementation grabs the instance from the current UnitOfWork
//If you want to look for it anywhere else you could write another implementation of IContextManager
public class ContextManager : IContextManager
{
public MyEntities GetContext()
{
return UnitOfWork.Current.GetContext();
}
}
//Repository provides CRUD operations with different entities
public class RepositoryBase
{
//Repository asks the ContextManager for the context, does not create it itself
protected readonly IContextManager _contextManager;
public RepositoryBase()
{
_contextManager = new ContextManager(); //You could also use DI/ServiceLocator here
}
}
//UsersRepository incapsulates Db operations related to User
public class UsersRepository : RepositoryBase
{
public User Get(Guid id)
{
return _contextManager.GetContext().Users.Find(id);
}
//Repository just adds/updates/deletes entities, saving changes is not it's business
public void Update(User user)
{
var ctx = _contextManager.GetContext();
ctx.Users.Attach(user);
ctx.Entry(user).State = EntityState.Modified;
}
}
public class ItemsRepository : RepositoryBase
{
public void UpdateSomeProperties(Item item)
{
var ctx = _contextManager.GetContext();
ctx.Items.Attach(item);
var entry = ctx.Entry(item);
item.ModifiedDate = DateTime.Now;
//Updating property1 and property2
entry.Property(i => i.Property1).Modified = true;
entry.Property(i => i.Property2).Modified = true;
entry.Property(i => i.ModifiedDate).Modified = true;
}
}
//Service encapsultes repositories that are necessary for request handling
//Its responsibility is to create and commit the entire UnitOfWork
public class AVeryCoolService
{
private UsersRepository _usersRepository = new UsersRepository();
private ItemsRepository _itemsRepository = new ItemsRepository();
public int UpdateUserAndItem(User user, Item item)
{
using(var unitOfWork = new UnitOfWork()) //Here UnitOfWork.Current will be assigned
{
_usersRepository.Update(user);
_itemsRepository.Update(user); //Item object will be updated with the same DbContext instance!
return unitOfWork.Commit();
//Disposing UnitOfWork: DbContext gets disposed immediately after it is not longer used.
//Both User and Item updates will be saved in ome transaction
}
}
}
//And finally, the Page
public class AVeryCoolPage : System.Web.UI.Page
{
private AVeryCoolService _coolService;
protected void Btn_Click(object sender, EventArgs e)
{
var user = .... //somehow get User and Item objects, for example from control's values
var item = ....
_coolService.UpdateUserAndItem(user, item);
}
}
I think you should read a bit more about repository pattern for EntityFramework and UnitofWork pattern.
Implementing the Repository and Unit of Work Patterns in an ASP.NET MVC
I know this is mvc and you are problably using web forms but you can get an idea of how to implement it.
Disposing the context on each request is a bit strange, because there might be requests where you will not touch the database, so you will be doing unnecessary code.
What you should do is get a layer for data access and implement a repository pattern that you will access on whatever method you will need on the code behind of your page.

Perform SQL Query WCF RIA Silverlight

I have created a database, linked it with DomainService's within my Silverlight Application. Now I want to be able to perform certain actions, such as Registration, Login etc. by using the service.
How would I be able to do this. I have preset methods created in the service, e.g. InsertUser but it only requires one parameter, so I'm not sure how it works. In the metadata I have all fields etc.
Can anyone help me out here.
Thanks.
public IQueryable<User> GetUsers()
{
return this.ObjectContext.Users;
}
public void InsertUser(User user)
{
if ((user.EntityState != EntityState.Detached))
{
this.ObjectContext.ObjectStateManager.ChangeObjectState(user, EntityState.Added);
}
else
{
this.ObjectContext.Users.AddObject(user);
}
}
For retrieving User I have used (as a base from TBohnen.jnr code):
UserContext _userContext = new UserContext();
public MainPage()
{
InitializeComponent();
LoadOperation loGetUsers = _userContext.Load(_userContext.GetUsersQuery());
loGetUsers.Completed += new EventHandler(loGetUsers_Completed);
}
void loGetUsers_Completed(object sender, EventArgs e)
{
LoadOperation<Web.User> lo = (LoadOperation<Web.User>)sender;
var user = _userContext.Users;
MessageBox.Show(user.ToString());
}
This is to add a new user:
YourDomainContext dc = new YourDomainContext();
User userToAdd = new User();
//You will have to set your properties here as I don't know them, I will give an example.
userToAdd.username = "NewUser";
dc.User.Add(userToAdd);
dc.SubmitChanges();
To retrieve your existing users:
YourDomainContext dc = new YourDomainContext();
LoadOperation loGetUsers = dc.Load(dc.GetUsersQuery());
loGetUsers.Completed += new EventHandler( loadOperation_Completed );// You will see there is a callback overloads as well
and then add this as well.
private void loadOperation_Completed( object sender, EventArgs e )
{
LoadOperation<User> lo = (LoadOperation<User>)sender;
//Have a look at all the properties like lo.Error etc. but to see the retrieved users you can either use:
var users = lo.AllEntities;
//or if you declared your domaincontext as a class level parameter:
var users = dc.User;
foreach (Web.User user in users)
{
MessageBox.show(user.username);
}
}
This will trigger an async call that get's all the users and will add it to the DomainContext and you will be able to access it through dc.User

Categories