How to access class method from view in asp.net mvc c#? - c#

I have controller : RecruitmentController.cs
and i have method/action : cekrecomended
public string cekrecomended(string id)
{
id = EncryptDecrypt.Decrypt(id);
string ada = "false";
string jurusan = Session["Jurusan"].ToString();
string pendidikan = Session["Pendidikan"].ToString();
int usia = Convert.ToInt16(Session["Usia"]);
string kelamin = Session["Kelamin"].ToString();
double nilai = Convert.ToDouble(Session["Nilai"]);
var data = (from c in db.ViewVacancyJabatanPerusahaans
where
c.Pendidikan.Contains(pendidikan) &&
(c.Jurusan.Contains(jurusan) || c.Jurusan.Contains("Semua jurusan")) &&
c.Nilai <= nilai &&
c.UsiaDari <= usia &&
c.UsiaSampai >= usia &&
c.JenisKelamin.Contains(kelamin) &&
c.TglAkhirlamaran >= DateTime.Now &&
c.Dlt == false &&
c.IDVancancy == Convert.ToInt16(id)
orderby c.IDVancancy descending
select c).Count();
if (data > 0)
{
ada = "true";
}
return ada;
}
i want to access cekrecomended from view.
#if(Human_Resource_Development.Controllers.RecruitmentController.cekrecomended(Convert.ToString(item.IDVancancy)) == "true")
{
<button>Apply this position</button>
}
but i get error.

This defeats the separation of model, view and controller MVC is based on - in your view you should just use your view model. In your case just use a view model that has a property making the result of this method call available.

You should use your view model for that purpose. Let's say MyViewModel is the class of your model, add a boolean property named IsRecommended
public class MyViewModel
{
// all of the other properties
// ....
public bool IsRecommended { get; set; }
}
Set the value of IsRecommended in your controller action method
public ActionResult Index()
{
MyViewModel model = new MyViewModel();
// other codes here
// ...
model.IsRecommended = ....; // logic from cekrecomended method here
return View(model);
}
Make sure you have this syntax at the top of your view
#model MyViewModel
and determine whether the "Apply this position" button will be displayed or not based on the value of IsRecommended property as below
#if (Model.IsRecommended)
{
<button>Apply this position</button>
}

Thank you for your answers. My problem solved, i have solution.
i just change
public string cekrecomended(string id)
{
//bla bla
}
to
public static string cekrecomended(string id)
{
//bla bla
}
and i can access from view.

Related

How to get the username of a logged in user and compare it to get the id

I want to be able to get the username of the logged in user in my C# ASP.net application so I can get the ID of that user. I then want to perform an edit so they can apply to be part of an appointment.
With my current code, I click the link and I just get a HTTP 400 error. I have debugged this and the ID is coming through as the correct value. Is there any reason that its not being attached to the url?
// GET:
public ActionResult VolunteerCeremony(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
string userName = string.Empty;
//if (System.Web.HttpContext.Current != null &&
// System.Web.HttpContext.Current.User.Identity.IsAuthenticated)
//{
// System.Web.Security.MembershipUser usr = System.Web.Security.Membership.GetUser();
// if (usr != null)
// {
// userName = usr.UserName;
// }
//}
var getVolunteerId = (from u in db.Volunteers
where WebSecurity.CurrentUserName == u.Username
select u.VolunteerId).FirstOrDefault();
Volunteer volunteer = db.Volunteers
.Include(p => p.Appointments)
.Where(i => getVolunteerId == id)
.FirstOrDefault();
if (volunteer == null)
{
return HttpNotFound();
}
PopulateAssignedCeremonyData(volunteer);
return View(volunteer);
}
// POST: /Player/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 ActionResult VolunteerCeremony(int? id, string[] selectedOptions)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var getVolunteerId = (from u in db.Volunteers
where WebSecurity.CurrentUserName == u.Username
select u.VolunteerId).FirstOrDefault();
var updateVolunteerWithCeremony = db.Volunteers
.Include(p => p.Appointments)
.Where(i => getVolunteerId == id)
.Single();
try
{
UpdateVolunteerCeremonies(selectedOptions, updateVolunteerWithCeremony);
db.Entry(updateVolunteerWithCeremony).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
catch (RetryLimitExceededException /* dex */)
{
//Log the error (uncomment dex variable name and add a line here to write a log.
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
}
PopulateAssignedCeremonyData(updateVolunteerWithCeremony);
return View(updateVolunteerWithCeremony);
}
EDIT This is where I'm calling the method
else if(Request.IsAuthenticated && HttpContext.Current.User.IsInRole("Volunteer"))
{
<li>#Html.ActionLink("Appointments", "Create", "Appointments")</li>
<li>#Html.ActionLink("Join Ceremony", "VolunteerCeremony", "Volunteers")</li>
}
EDIT 2 Here's my ViewModel that I used for the many to many relationship I have:
public class VolunteerCeremonyVM
{
public int AppointmentId { get; set; }
public string DetailsOfAppointment { get; set; }
public bool Assigned { get; set; }
public VolunteerCeremonyVM()
{
this.AppointmentId = AppointmentId;
this.DetailsOfAppointment = DetailsOfAppointment;
this.Assigned = Assigned;
}
}
Based on further clarification, you will want to update your ViewModel to include a VolunteerId. So it should look something like:
public class VolunteerCeremonyVM
{
public int AppointmentId { get; set; }
public string DetailsOfAppointment { get; set; }
public bool Assigned { get; set; }
public int VolunteerId { get; set; }
}
Notice that I removed the default constructor as it wasn't doing anything. When you construct the object you can use code like the following:
var model = new VolunteerCeremonyVM {
AppointmentId = 10,
VolunteerId = 50,
//etc
};
As this will set all of the properties after the basic object is constructed.
Then, you will want to pass this view model into the view that is generating your action links like so: return View(model); in whatever controller action you're using.
Inside the view, you will make use of this new information. Specifically, the Html.ActionLink method requires that any extra parameters are passed to it in a route dictionary. It uses this route dictionary to build the URL that is generated for the anchor tag. You can call Html.ActionLink with an anonymous object for its fourth parameter to specify the route dictionary. The id will be the name of the parameter and Model.VolunteerId will be the value of the current volunteer.
Change the Html.ActionLink call to the following to pass an id:
#Html.ActionLink("Join Ceremony",
"VolunteerCeremony",
"Volunteers",
new { id = Model.VolunteerId },
null)
This should fill in the id parameter of the ActionLink with the currently logged in user's userId which should generate the following link: /Volunteers/VolunteerCeremony/3 or whatever the ID actually is.
For the form side, you will also need a hidden field on the form so the correct id is sent along with the request. You will need to add a VolunteerId to the form ViewModel that you create when generating the form page. Once you've done that, inside the form itself, you will need to add the following:
Html.Hidden("id", Model.VolunteerId)
This creates an <input type="hidden" name="id" value="3" /> tag that will be sent with the form on post back to the server. Since the tag's name is id this will match with the id that's defined in your controller action.

Passing string from model that is created on certain condition

I just happaned to have some troubles.
I have a model with a function
public class Profile
{
public void PrintResult()
{
if(1 == 1)
{
Console.WriteLine("equals 1");
if(2 == 2)
{
Console.WriteLine("equals 2");
}
}
else
{
Console.WriteLine("error");
}
}
}
this is the controller:
public ActionResult Index()
{
Profile p = new Profile();
p.PrintResult();
return View();
}
Well, I know that console.writeline or response.write.
So, my question is: how could I make those console.writeline to things like
string s = "Equals 2";
instead of console.writelines which does not working obviously and then call it somehow both equals 1 and equals 2 show in the view.
Been googling for quite long and couldn't find an answer.
If you need more info to help me, tell me #_ #
Instead of console.writeline, you have to return comma seperated string Or list of string
public List<string> PrintResult()
{
var listItems = new List<string>();
if (1 == 1)
{
listItems.Add("equal 1");
if (2 == 2)
{
listItems.Add("equal 2");
}
}
else
{
listItems.Add("error");
}
return listItems;
}
Return a comma separated list from your model in this case(Though i do not support coding such kind of models.Think this is for your practise).
public class Profile
{
public string PrintResult()
{
string strSample="";
if(1 == 1)
{
if(strSample=="")
{
strSample="equals 1";
}
else
{
strSample+=","+"equals1";
}
if(2 == 2){
if(strSample=="")
{
strSample="equals 2";
}
else
{
strSample+=","+"equals2";
}
|
}else
{
if(strSample=="")
{
strSample="error";
}
else
{
strSample+=","+"error";
}
}
}
}
Now In your controller pass this string returned from the model to your view as follows
public ActionResult Index()
{
Profile p = new Profile();
string sample=p.PrintResult();
return View((object)sample);
}
Now in your Index View, make the view as strongly typed to a string like below
#model string
<h1>#Model</h1>

How to keep CheckBox value after a get?

In my ASP.NET MVC 5 website i have this situation:
I have a GridView that i can get just the default rows or all the rows(including the deleted ones). Im trying to control that using a CheckBox in the ribbon of the view called 'cbxGetAll'.
So, here is my script:
<script>
function OnCommandExecuted(s, e) {
if (e.item.name == "cbxGetAll") {
if (e.parameter) {
window.location.href = '#Url.Action("Index",new {getAll = true})';
return;
} else {
window.location.href = '#Url.Action("Index",new {getAll = false})';
return;
}
}
</script>
And my Action:
public ActionResult Index(bool? getAll)
{
if (getAll != null && (bool) getAll)
{
//Return Without Filter
}
else
{
//Return With Filter
}
}
I change the getAll parameter in the URL and it works well.
But the problem is that when the ActionResult completes, it reloads the page (of course) and then i lost the checkbox state.
How can i deal with this?
It's all about view models. You should be returning a view model that has the value of your checkbox, and have your view use that value. If you are also returning data, simply place the data (whatever it is) inside your view model as well.
Example:
public class MyViewModel
{
public bool GetAll { get; set; }
public SomeDataModel[] MyData { get; set; }
}
public ActionResult Index(bool? getAll)
{
SomeDataModel[] data;
if (getAll != null && (bool) getAll)
{
var data = GetSomeData(true);
}
else
{
var data = GetSomeData(false);
}
return View(new MyViewModel() { MyData = data, GetAll = getAll == true });
}

How to use if else in this action?

How do you write an if/else statement for this method if there is no result?
public ActionResult Search(string q)
{
Helpers Helpers = new Helpers();
var restaurants = Helpers.getRestaurant(q);
return View("_RestaurantSearchResults", restaurants);
}
Helpers class contains:
public class Helpers
{
FoodReviewContext _db = new FoodReviewContext();
public static IQueryable<Restaurant> getRestaurant(string q)
{
var restaurents = _db.Restaurants
.Where(r => r.Name.StartsWith(q) || String.IsNullOrEmpty(q))
.Take(2);
return restaurents;
}
}
If I understand your question correctly:
public ActionResult Search(string q)
{
Helpers Helpers = new Helpers();
var restaurants = Helpers.getRestaurant(q);
if (restaurants.Count() == 0) {
// do something
} else {
// do something else
}
return View("_RestaurantSearchResults", restaurants);
}
Take a look here: http://msdn.microsoft.com/en-us/library/bb351562%28v=vs.110%29.aspx. This goes over all the methods in the IQueryable<T> interface.
Oftentimes when you are looking for how to work with a certain part of the .NET Framework, C#, or others' code, the documentation is the best first place to go to.
simply check your result count for it.
public ActionResult Search(string q)
{
Helpers Helpers = new Helpers();
var restaurants = Helpers.getRestaurant(q);
if(restaurants.Count()>0)
{
return View("_RestaurantSearchResults", restaurants);
}
else
{
ViewBag.Message="No result found";
return View("_RestaurantSearchResults");
}
}
And just check if ViewBag.Message is available or not in View.
Try this
if (restaurants.Count() != 0)
{
//non-zero thing
}
else
{
//zero thing
}

Reuse model data in a post action

In my viewmodel, I have a list of items I fetch from the database and then send to the view. I would like to know if it's possible to avoid having to refill the options property whenever I hit a Post action and need to return the model (for validation errors and what not)?
In webforms, this wouldn't be necessary.
Edit: I was not clear. My problem is with the SelectList options I use for my DropDownLists. Everything gets posted, but if I have to return to the view (model is invalid), I have to reload the options from the database! I want to know if this can be avoided.
My viewmodel:
public class TestModel
{
public TestModel()
{
Departments = new List<SelectListItem>();
}
public string Name { get; set; }
public int Department { get; set; }
public IEnumerable<SelectListItem> Departments { get; set; }
}
My view:
#model MvcApplication1.Models.TestModel
#using (Html.BeginForm())
{
#Html.TextBoxFor(m => m.Name)
#Html.DropDownListFor(m => m.Department, Model.Departments)
<input type=submit value=Submit />
}
My controller (do notice the comment on HttpPost):
public ActionResult Index()
{
TestModel model = new TestModel
{
Name = "Rafael",
Department = 1,
Departments = new List<SelectListItem>
{
new SelectListItem { Text = "Sales", Value = "1" },
new SelectListItem { Text = "Marketing", Value = "2", Selected = true },
new SelectListItem { Text = "Development", Value = "3" }
}
};
// Departments gets filled from a database.
return View(model);
}
[HttpPost]
public ActionResult Index(TestModel model)
{
if (!ModelState.IsValid)
{
//Do I have to fill model.Departments again!?!?!?
return View(model);
}
else { ... }
}
Thanks in advance.
Edit: FYI, my solution was to use the Session variable.
Just need to strongly type your view, and change your controller method to have a parameter of that class type.
That is, the view
#model MyNamesspace.Models.MyModel
...
#using (Html.BeginForm())
{
....
}
And you controller method which is posted to.
[HttpPost]
public ActionResult MyAction(MyModel model)
{
...
}
EDIT: Also make sure you have form fields for each property of the model which you need posted to the controller. My example is using Razor too BTW.
I encountered a similar problem when trying to create an Order wizard in MVC (one where each page of the wizard is implemented as a partial view loaded by AJAX). I highly doubt it is the suggested method but my way of solving this was to call a custom MergeChanges method in each action called by my wizard:
public Order MergeChanges(Order newOrder)
{
var sessionHistory = (List<string>)Session["sessionHistory"];
if (sessionHistory == null || sessionHistory.Count == 0)
return MergeChanges(newOrder, -1);
return MergeChanges(newOrder, MasterViewController.GetStepNumberByName(sessionHistory.Last()));
}
public Order MergeChanges(Order newOrder, int step)
{
PreMerge(newOrder);
Order result = null;
try
{
ApplyLookups(ref newOrder);
Order oldOrder = (Order)Session["order"];
if (oldOrder == null)
{
Session["order"] = newOrder;
result = newOrder;
}
else
{
List<TypeHelper.DecoratedProperty<ModelPageAttribute>> props = null;
newOrder.GetType().GetDecoratedProperty<ModelPageAttribute>(ref props);
props = props.Where(p => (p.Attributes.Count() > 0 && p.Attributes.First().PageNumber.Contains(step))).ToList();
foreach (var propPair in props)
{
object oldObj = oldOrder;
object newObj = newOrder;
if (!string.IsNullOrEmpty(propPair.PropertyPath))
{
bool badProp = false;
foreach (string propStr in propPair.PropertyPath.Split('\\'))
{
var prop = oldObj.GetType().GetProperty(propStr);
if (prop == null)
{
badProp = true;
break;
}
oldObj = prop.GetValue(oldObj, BindingFlags.GetProperty, null, null, null);
newObj = prop.GetValue(newObj, BindingFlags.GetProperty, null, null, null);
}
if (badProp)
continue;
}
if (newObj == null)
continue;
var srcVal = propPair.Property.GetValue(newObj, BindingFlags.GetProperty, null, null, null);
var dstVal = propPair.Property.GetValue(oldObj, BindingFlags.GetProperty, null, null, null);
var mergeHelperAttr = propPair.Property.GetAttribute<MergeHelperAttribute>();
if (mergeHelperAttr == null)
{
if (newObj != null)
propPair.Property.SetValue(oldObj, srcVal, BindingFlags.SetProperty, null, null, null);
}
else
{
var mergeHelper = (IMergeHelper)Activator.CreateInstance(mergeHelperAttr.HelperType);
if (mergeHelper == null)
continue;
mergeHelper.Merge(context, HttpContext.Request, newObj, propPair.Property, srcVal, oldObj, propPair.Property, dstVal);
}
}
result = oldOrder;
}
}
finally
{
PostMerge(result);
}
return result;
}
Since my case was doing this with a wizard, only specific values applied to each page so in order to only account for properties known to the current page of the wizard, I've implemented some attributes, a (admittedly over complex) ViewController layer, and a custom validation layer. I can share some more code but the code above does the grunt work if you aren't in such a complex situation. If there is a better way, I hope to learn it from the answers to this question because this was a PITA.
I am surprised this question doesn't come up more often, and I am also surprised the obvious (IMHO) answer isn't standard practice these days: nearly all POSTs should be Ajax-based. This solves a whole slew of problems including
No need to repopulate form data when you have e.g. a validation error, or application error (exception). This is particularly desirable when you have client-side state (in true rich web application fashion).
No compulsion to perform client-side validation. Validation can be 100% server-side (where it must be anyways) and the user experience is nearly the same.
Of course, there is some initial work you need to do to build out a framework for this, for example, I have a set of AjaxUpdate, AjaxNothing, AjaxRedirect, AjaxErrors ... ActionResult types which render Json which is processed by some custom Javascript. But once you get that in place, it's smooth sailing.

Categories