I just followed an MVC tutorial on creating an image Gallery, which connects the Controller to the data connection, like this:
ImageController.cs:
...
private CustomMembershipDB db = new CustomMembershipDB();
public ViewResult Index()
{
return View(db.lm_pics.ToList());
}
...
Instead of connecting directly to CustomMembershipDB, I'd like to use my own Model named GalleryModel.cs. I'm thinking this would allow me to create more functionality that just direct data access.
I am not sure how to write this model, or how to reference it in the controller so that it behaves the same way as a direct database connection does now.
Currently, my GalleryModel.cs file looks lke this (edited to correct error):
namespace LMProj_MVC.Models
{
public class GalleryModel
{
public string Picname { get; set; }
public string Decription{ get; set; }
public int Userid { get; set; }
}
public class PicDBContext : CustomMembershipDB
{
public DbSet<GalleryModel> GalleryModel { get; set; }
}
}
I'd like to be able to show the gallery using an iEnumberable list as I am doing now, in addition to creating other methods. Could someone tell me what I'm missing?
You need to create an instance of your model object for each of your database pictures. You could use LINQ to do this, for example:
var picSummaries = db.lm_pics.Select(pic => new GalleryModel{
Picname = pic.Name,
Description = pic.Description,
Userid = pic.User.Id
});
Or you could use a for each loop:
var picSummaries = new List<GalleryModel>();
foreach (var pic in db.lm_pics)
{
picSummaries.Add(new GalleryModel{
Picname = pic.Name,
Description = pic.Description,
Userid = pic.User.Id
});
}
then return the view as before:
return View(picSummaries);
Related
I am recently starting to learn mobile development for my Final Year Project, and I am doing an Android application using Xamarin.Android and Azure Mobile Services.
I have created a Test DB and created one entry there, trying to make my Android App to connect to the DB and retrieve this entry. I am doing this to get an idea how to establish a connection and retrieve data, and from there I will start modification properly.
That is how my Model class look like (note that JSON properties are named exactly like the columns names in my DB.
using Newtonsoft.Json;
namespace com.parkkl.intro.Models
{
class TestTable
{
public int Id { get; set; }
[JsonProperty(PropertyName = "UserName")]
public string UserName { get; set; }
[JsonProperty(PropertyName = "deleted")]
public bool Deleted { get; set; }
[JsonProperty(PropertyName = "version")]
public string Version { get; set; }
[JsonProperty(PropertyName = "createdAt")]
public string Creation { get; set; }
[JsonProperty(PropertyName = "updatedAt")]
public string Updated { get; set; }
}
}
And that is how my activity look like
using Android.App;
using Microsoft.WindowsAzure.MobileServices;
using Android.OS;
using com.parkkl.intro.Models;
using System.Collections.Generic;
using Android.Widget;
namespace com.parkkl.intro
{
[Activity(Label = "ParkKL", MainLauncher = false, Icon = "#drawable/icon")]
public class MainActivity : Activity
{
#region Variables
public static MobileServiceClient client = new MobileServiceClient
(#"http://parkkl.azurewebsites.net/");
private IMobileServiceTable<TestTable> test = null;
private List<TestTable> testItems;
#endregion
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
test = client.GetTable<TestTable>();
testItems = new List<TestTable>();
GetData();
}
public async void GetData()
{
var collection = await test.Where(user => user.Id == 1).ToCollectionAsync();
foreach (var item in collection)
{
testItems.Add(
new TestTable
{
Id = item.Id,
UserName = item.UserName,
Deleted = item.Deleted,
Version = item.Version,
Creation = item.Creation,
Updated = item.Updated,
});
}
var finalItem = collection[0];
TextView text = (TextView)FindViewById(Resource.Id.TextFromDB);
text.Append(finalItem.UserName);
}
}
}
Now the issue is, every time I try to deploy the app, it throws this exception
Microsoft.WindowsAzure.MobileServices.MobileServiceInvalidOperationException:
You must be logged in to use this application
In my App Service in Azure, I have disabled all authentications, still I get this error. I am wondering where the issue is coming from?! I will much appreciate your help.
EDIT: I guess I found the issue, which was the permissions given on the table itself. However, I am still finding out a way to authenticate my app properly
Check out the book http://aka.ms/zumobook for details on how to deal with authentication.
I have a table where I store all the different code/value keywords that I need in my app:
public class Keyword
{
public int id { get; set;}
public string name { get; set; }
public string valuecode { get; set; }
public string valuename { get; set; }
}
Then I use Keyword to store records like these
name valuecode valuename
.DealState 1 Draft
.DealState 2 Final
.DealState 3 Cancelled
.DealType NEW New Business
.DealType RNW Renewal
.DealType WFA Waiting for approval
Then in other models I have fields that are filled using these keywords. For example,
public class Deal
{
....
public string state { get; set; }
public string type { get; set; }
....
}
I have managed to have the fields filled with "valuecode" while displaying "valuename" in Create and Edit views (I use DropDownList with a SelectList built in the controller), but I cannot find a way to display valuename instead of valuecode in Index and Details views.
I'm trying to pass the same SelectList in the ViewBag for Index, but then I do not know which syntax to use in order to replace the "state" code with the state "description" for each record returned.
Any hint?
PS: I'm quite new to .net and mvc, usually work with RoR and ActiveRecord...
EDIT
In my KeywordController I have a method
public SelectList selectKeywordValues(string kwname, object selectedKeyword = null)
{
var keywordsQuery = from d in db.Keywords
where d.name == kwname
orderby d.valuename
select d;
SelectList kwlist = new SelectList(keywordsQuery, "valuecode", "valuename", selectedKeyword);
return kwlist;
}
Then in my DealController i have the index method
public ActionResult Index()
{
var kw = new KeywordController();
ViewBag.state = kw.selectKeywordValues(".DealState");
return View(db.Deals.ToList());
}
SOLVED
In DealController the index method is the following
public ActionResult Index()
{
var kw = new KeywordController();
SelectList states = kw.selectKeywordValues(".DealState");
SelectList types = kw.selectKeywordValues(".DealType");
foreach (var item in db.Deals.ToList())
{
SelectListItem mystate = states.Where(row => row.Value == item.state).ElementAt(0);
SelectListItem mytype = types.Where(row => row.Value == item.type).ElementAt(0);
item.state = mystate.Text;
item.type = mytype.Text;
}
return View(db.Deals.ToList());
}
Now the db.Deals.ToList() is filled with descriptions and not with codes.
You can define a view model called DealViewModel that contains DealState and DealType properties. Then populate the DealViewModel with joins in LINQ before passing to the views that reference the view model.
Another approach is to use enums in EF5.
Perhaps there is an easy solution for my problem but I simply cannot seem to find it. I have read lots of tutorials about Knockout so I get the basics but I ask this question because my entity-structure is a bit more complicated than a person with a name and a list of friends which may or may not be on Twitter (Video on Channel9: Helping you build dynamic JavaScript UIs with MVVM and ASP.NET). Here's my situation:
I have a class PersonnelClass with this basic structure:
[Serializable]
//The interface is for the implementation of 'Name' and 'Description'
public class PersonnelClass : IPersonnelClassOrPerson
{
public PersonnelClass() : this(Guid.NewGuid(), "", "") { }
public PersonnelClass(Guid id, String name, String description = null)
{
if (id == Guid.Empty) { throw new ArgumentNullException("id"); }
Id = id;
Name = name;
Description = description;
Properties = new PropertyCollection();
}
public Guid Id { get; private set; }
public String Name { get; set; }
public String Description { get; set; }
public PropertyCollection Properties { get; private set; }
}
The PropertyCollection class and associated AbstractProperty class look like this:
[Serializable]
public class PropertyCollection: List<AbstractProperty> { }
[Serializable]
public abstract class AbstractProperty: IEntity, IProperty
{
public AbstractProperty(String name, String description = null) : this(Guid.NewGuid(), name, description) { }
public AbstractProperty(Guid id, String name, String description = null)
{
if (id == Guid.Empty) { throw new ArgumentNullException("id"); }
if (String.IsNullOrEmpty(name)) { throw new ArgumentNullException("name"); }
Id = id;
Name = name;
Description = description;
}
public Guid Id { get; private set; }
public String Name { get; private set; }
public String Description { get; private set; }
}
In my Controller, I create an instance of a PersonnelClassViewModel that has this structure:
public class PersonnelClassViewModel
{
public PersonnelClass PersonnelClass { get; set; }
public List<AbstractProperty> Properties { get; set; }
}
I fill this viewmodel with a new PersonnelClass and two test-properties to pass to my View like this:
var properties = new List<AbstractProperty>
{
new TextProperty("prop1", "descr1"),
new TextProperty("prop2", "descr2")
//TextProperty is derived from AbstractProperty
};
var vm = new PersonnelClassViewModel { Properties = properties };
return View(vm);
I get everything in my View as I wanted. From the View I want to create a new PersonnelClass with a set of selected properties. I have the fields for Name and Description and to add the properties I have a ListBox with the properties that already exist (for demo-purpose they came from the controller now). Through a bit of Knockout JavaScript code I can select items from this list and populate an HTML select-control () with the selected properties to add to the PersonnelClass. This all works fine, until I want to build up an object to pass back to the Controller and create the PersonnelClass.
My question is: what Knockout JS code is needed to build up this object and pass it to the Controller by submitting the form and in my Controller how should I receive this object, meaning: what type of object should this be (PersonnelClass, PersonnelClassViewModel, ...) ?
If any more info/code is needed, please do ask. Thanks in advance!
Update after answer of 'B Z':
I followed a few more of Steven Sanderson's tutorials about this to be sure I understand this, especially the one you provided in your answer. Now I have following code in my View to start with:
var initialData = #Html.Raw(new JavaScriptSerializer().Serialize(Model));
var viewModel = {
personnelClassViewModel : ko.mapping.fromJS(initialData),
properties : personnelClassViewModel.Properties,
selectedProperties : ko.observableArray([]),
addedProperties : ko.observableArray([])
};
ko.applyBindings(viewModel);
The variable 'initialData' contains the values I expect it to have but then I get the following error:
Microsoft JScript runtime error: 'personnelClassViewModel' is undefined
I have no clue anymore. Can anyone help me fix this?
Steven Sanderson has an example of how to to work with variable length lists and knockoutjs
http://blog.stevensanderson.com/2010/07/12/editing-a-variable-length-list-knockout-style/
Having said that, I think your problem isn't so much on the knockout side and more on the how to databind the data correctly on the server side. In the link above, Steven uses a FromJson attribute to model bind which you may find useful...
HTH
I would like to use Linq and strongly typed views in the right way. at the moment I do the following:
Make a Model to verify agianst:
public class Menu
{
public int Id { get; private set; }
public string Text { get; private set; }
public string Action { get; private set; }
public string Controller { get; private set; }
public string Parameter { get; private set; }
public string Langue { get; private set; }
public Menu(int id, string controller, string action, string parameter, string text)
{
Id = id;
Controller = controller;
Action = action;
Text = text;
Parameter = parameter;
}
Use Linq to get the data from the database into the model:
public static List<Menu> GetTabListForMenu(string langue)
{
Page_dbEntities entity = new Page_dbEntities();
var tabList = (from ml in entity.wpmenulangue
where ml.Langue == langue
from m in entity.wpmenu
where ml.Menu == m.Id
from l in entity.wplangue
where ml.Langue == l.Langue
from p in entity.wppage
where p.Id == m.Page
select new { m.Id, p.Controller, p.Action, p.Parameter, ml.Text}).ToList();
List<Menu> menu = new List<Menu>();
foreach (var item in tabList)
{
menu.Add(new Menu(item.Id, item.Controller, item.Action, item.Parameter, item.Text));
}
return menu;
}
I am pretty convinced that this is not the optimal way to do this and have 2 questions:
When I get the data from the database I first use a var and then have to move it to the object with a foreach. this seems like a waste of both my time and less effeicent then getting it with sql.
I have been told that I can just verify up agianst the entitymodel. Even if i use multiple entities in a view. is this true? (the one telling me this wes not able to get it to work and I have not been able to find anything about it online).
I will try to look back on this post in the next couple of hours, but might have to wait 24 hours.
public static List<Menu> GetTabListForMenu(string langue)
{
Page_dbEntities entity = new Page_dbEntities();
return (from ml in entity.wpmenulangue
where ml.Langue == langue
from m in entity.wpmenu
where ml.Menu == m.Id
from l in entity.wplangue
where ml.Langue == l.Langue
from p in entity.wppage
where p.Id == m.Page
select new Menu(m.Id, p.Controller, p.Action, p.Parameter, ml.Text)
).ToList();
}
As for the validation is concerned you shouldn't use multiple entities in the view. You should use a single entity which is called ViewModel. This ViewModel is a class that represents the data on the view. If you are using DataAnnotations for validation you could decorate this view model properties with attributes that indicate how to be validated.
Id like to have my mvc 2 app generating reports in both MS Word and PDF formats....currently working on Word. I found this:
http://www.revium.com.au/articles/sandbox/aspnet-mvc-convert-view-to-word-document/
Which i think basically streams the view output from a controller action to a word document....
public ActionResult DetailedReport()
{
//[...]
return View();
}
public ActionResult DetailedReportWord()
{
string url = "DetailedReport";
return new WordActionResult(url, "detailed-report.doc");
}
And heres the class that extends ActionResult
public class WordActionResult : ActionResult
{ private string Url { get; set;}
private string FileName { get; set;}
public WordActionResult(string url, string fileName)
{
Url = url;
FileName = fileName;
}
public override void ExecuteResult(ControllerContext context)
{
var curContext = HttpContext.Current;
curContext.Response.Clear();
curContext.Response.AddHeader("content-disposition", "attachment;filename=" + FileName);
curContext.Response.Charset = "";
curContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
curContext.Response.ContentType = "application/ms-word";
var wreq = (HttpWebRequest) WebRequest.Create(Url);
var wres = (HttpWebResponse) wreq.GetResponse();
var s = wres.GetResponseStream();
var sr = new StreamReader(s, Encoding.ASCII);
curContext.Response.Write(sr.ReadToEnd());
curContext.Response.End();
}
}
Which looks pretty good - but my problem is that my view renders from a ViewModel, here is the Action
[HttpPost]
public ActionResult StartSearch(SearchResultsViewModel model)
{
SearchResultsViewModel resultsViewModel = _searchService.Search(model.Search, 1, PAGE_SIZE);
return View("Index", resultsViewModel);
}
and here is my model:
public class SearchResultsViewModel
{
[SearchWordLimit]
public string Search { get; set; }
public IEnumerable<Employee> Employees { get; private set; }
public IEnumerable<Organization> Organizations { get; private set; }
public PageInfo PageInfo { get; private set;}
public SearchResultsViewModel()
{
}
public SearchResultsViewModel(string searchString, IEnumerable<Employee> employees, IEnumerable<Organization> organizations, PageInfo pageInfo)
{
Search = searchString;
Employees = employees;
Organizations = organizations;
PageInfo = pageInfo;
}
}
I'm having trouble kinda connecting the two - to stream the view using my viewmodel to pdf
There's nothing out of the box in ASP.NET MVC that allows you to build a PDF or Word file from a POCO class. You have to build it manually or using a third party library. Once you have done this you could easily write the bytes to the response stream:
public ActionResult SomeAction(SearchResultsViewModel model)
{
byte[] pdf = GeneratePdfForModel(model);
return File(pdf, "application/pdf");
}
The GeneratePdfForModel method will of course be specific on what library/API you are using to generate the document.
The trick is to generate the PDF file from the MS-Word file. You most likely need a 3rd party component for this.
If you don't need perfect conversion fidelity, just something that is 'good enough', then try Aspose.Words. If you need perfect conversion Fidelity then try a product I have worked on, it allows the conversion of all typical MS-Office types to PDF format using a web services interface.
I'm a bit late to this, but from what I can see:
public ActionResult DetailedReportWord()
{
string url = "DetailedReport";
return new WordActionResult(url, "detailed-report.doc");
}
Your url is pointing back to the same Action, it should be pointing at your "StartSearch" action as that is the one that produces the HTML you are wanting to be opened by Word. It needs to be a full URL too I think.
I am trying to use this method too, I found it from your question! I'm having issues passing over the authorised credentials in the WebRequest.Create(Url) for the source View however.