I am calling a API method that is returning some question and answer as List. I need show this list in View, not sure how to add value to the faq list. As I am sending this List that is part of Model to the View to show in on the screen.
Inside the foreach loop is where I have to add value of web api to the faq List.
This is my method which is returning the Model.
[HttpGet]
public async Task<ActionResult> ShowContact(int loanId)
{
HelpCenterViewModel helpCenterViewModel = new HelpCenterViewModel();
helpCenterViewModel.ContactInfo.loanId = loanId;
string json = string.Empty;
List<Faq> FaqObject = null;
var responseApi = await httpClient.GetAsync(string.Format("{0}/{1}",
CommonApiBaseUrlValue, "faqs"));
if (responseApi.IsSuccessStatusCode)
{
json = responseApi.Content.ReadAsStringAsync().Result;
FaqObject = new JavaScriptSerializer().Deserialize<List<Faq>>(json);
}
var response = new
{
success = FaqObject != null,
data = FaqObject
};
foreach (var faqitem in response.data)
{
//This is where I dont know how to add to faq list.
//helpCenterViewModel.Faq.Answer = faqitem.Answer;
//helpCenterViewModel.Faq.Category = faqitem.Category;
}
return View(helpCenterViewModel);
}
This is the Model that I am retunign it to view:
public class HelpCenterViewModel
{
public List<Faq> Faq { get; set; }
public ContactUsInfo ContactInfo { get; set; }
public HelpCenterViewModel()
{
this.Faq = new List<Faq>();
this.ContactInfo = new ContactUsInfo();
}
}
and this is the faq class:
public class Faq
{
public int Id { get; set; }
public string Category { get; set; }
public string Question { get; set; }
public string Answer { get; set; }
}
and this is my view:
#model IEnum erable<Carfinance.Loans.Web.ViewModels.HelpCenterViewModel>
#foreach (var item in Model)
{
<li>#Html.DisplayFor(faq => item.Faq)</li>
}
But It gave me this error.
The 'DelegatingHandler' list is invalid because the property 'InnerHandler' of 'CorsMessageHandler' is not null.
Parameter name: handlers
You need to create a new object for each of your items and add them to your list. This can be done in various ways, depending on how verbose you want your implementation to be:
foreach (var faqitem in response.data)
{
var faq = new Faq();
faq.Answer = faqitem.Answer;
faq.Category = faqitem.Category;
helpCenterViewModel.Faq.Add(faq);
}
OR
foreach (var faqitem in response.data)
helpCenterViewModel.Faq.Add(new Faq()
{
Answer = faqitem.Answer;
Category = faqitem.Category;
});
OR
helpCenterViewModel.Faq = response.data.Select(x => new Faq {
Answer = x.Answer,
Category = x.Category
}).ToList();
Cleaned up the code some, but you already have a List<Faq>, so just assign it to your model.
[HttpGet]
public async Task<ActionResult> ShowContact(int loanId)
{
string json = string.Empty;
List<Faq> FaqObject = null; // Should probably be new List<Faq>
var responseApi = await httpClient.GetAsync(string.Format("{0}/{1}", CommonApiBaseUrlValue, "faqs"));
if (responseApi.IsSuccessStatusCode)
{
json = responseApi.Content.ReadAsStringAsync().Result;
FaqObject = new JavaScriptSerializer().Deserialize<List<Faq>>(json);
}
var response = new
{
success = FaqObject != null,
data = FaqObject
};
return View(new HelpCenterViewModel
{
ContactInfo=new ContactInfo {loanId},
Faq=FaqObject
});
}
Not sure what you were doing with the response variable, so I just left it there, but it appears to do nothing useful and could be removed as well. Then you'd have this:
[HttpGet]
public async Task<ActionResult> ShowContact(int loanId)
{
var responseApi = await httpClient.GetAsync(string.Format("{0}/{1}", CommonApiBaseUrlValue, "faqs"));
if (responseApi.IsSuccessStatusCode)
{
return View(new HelpCenterViewModel
{
ContactInfo=new ContactInfo {loanId},
Faq=new JavaScriptSerializer().Deserialize<List<Faq>>(
responseApi.Content.ReadAsStringAsync().Result)
});
}
return View(new HelpCenterViewModel
{
ContactInfo=new ContactInfo {loanId},
Faq=new List<Faq>()
});
}
well, the Faq property on HelpCenterViewModel is really a List<Faq> (kind of misleading naming you have there), so use the Add method:
foreach (var faqitem in response.data)
{
var faq = new Faq();
faq.Answer = faqitem.Answer;
faq.Category = faqitem.Category;
helpCenterViewModel.Faq.Add(faq);
//^ this Faq is a List
}
You should pluralize your List<Faq>'s name to Faqs to prevent confusing yourself.
Related
I want to pass the result of a cypher query to MVC's view using model. The obtained result is in form of nodes which I get in var result.
Now I want to pass this result to a view as model, so that I can print the obtained result in a razor view.
My model class is as:
public class Item {
public int id {get; set;}
public string name {get; set;}
public string type {get; set;}
}
And my controller method is as:
public ActionResult Index()
{
using(var driver = GraphDatabase.Driver("bolt://localhost:7687","neo4j", "12345")
{
using(var session = driver.Session())
{
using(var tx = session.ReadTransaction())
{
var result = tx.Run("MATCH (m:Item) RETURN m")
}
}
}
return View();
}
Finally I solved my problem. Thanks to #Chris Skardon. Below is the code that solved my problem.
public ActionResult Index()
{
// Using Neo4j.Driver
List<Item> items = new List<Item>();
using (var session = _driver.Session())
{
var results = session.ReadTransaction(tx => tx.Run("MATCH (a:Item) RETURN (a)"));
foreach(IRecord result in results)
{
var Node = result["a"].As<INode>();
var Id = node.Properties["ID"]?.As<long>();
var Name = node.Properties["Name"]?.As<string>();
var Type = node.Properties["Type"]?.As<string>();
items.Add(new Item { id = Id, name = Name, type = Type });
}
return View(items.ToList());
}
}
Update: I fixed it by copy pasting the working code into a new clean project. I have no idea why I was getting that bug, but as long as it's gone
I'm having problems figuring exactly how to do what I want.
In this instance, what I have is a db of merchants, and I want to be able to add venues as a list to the merchant entry in the database. For some reason I cannot figure out why, I can fetch the merchant, but cannot seem to get a hold of the id of the entry that I have fetched and then update it. (I'm having some problems with updating as well, From what I've seen I need the Id of the entry I want, and then I can update with a patch... right?)
Here is my Json class:
public class Merchant
{
[JsonProperty(PropertyName = "name")]
public string name { get; set; }
[JsonProperty(PropertyName = "venues")]
public List<Venue> venues { get; set; }
}
public class Venue
{
[JsonProperty(PropertyName = "name")]
public string name { get; set; }
[JsonProperty(PropertyName = "tills")]
public List<Till> tills { get; set; }
}
public class Till
{
[JsonProperty(PropertyName = "name")]
public string name { get; set; }
}
Here's my RavenDB Handler class's functions that are relevent:
public List<JObject> QueryFromDb(string query)
{
List<Object> objReturned;
List<JObject> jObjects = new List<JObject>();
using (IDocumentSession session = store.OpenSession())
{
objReturned = session
.Advanced.RawQuery<Object>(query)
.ToList();
}
for (var i = 0; i < objReturned.Count; i++)
{
var json = JsonConvert.SerializeObject(objReturned[i], Formatting.Indented);
jObjects.Add(JObject.Parse( json.ToString()));
}
return jObjects;
}
public String GetJsonFromDB(string query)
{
string returnStr = "";
List<JObject> myResponse = QueryFromDb(query);
for (var i = 0; i < myResponse.Count; i++)
{
var json = JsonConvert.SerializeObject(myResponse[i], Formatting.Indented);
returnStr += json.ToString();
}
return returnStr;
}
And here is me trying to get ahold of the Id of the ravendb entry:
public void UpdateMerchantList()
{
merchantGrid.Rows.Clear();
List<JObject> myResponse = ravenDB.QueryFromDb("from Merchants");
for (var i = 0; i < myResponse.Count; i++)
{
var json = JsonConvert.SerializeObject(myResponse[i], Formatting.Indented);
Merchant merchant = new Merchant(json.ToString());
if (myResponse[i].Property("Id") != null) { merchant.MyID = myResponse[i].Property("Id").ToString(); }
merchantGrid.Rows.Add(merchant.MyID, merchant.name);
}
}
For some reason, I took this code and transplanted it into a console app, and got it to work with this code:
List<JObject> result = ravenDb.QueryFromDb("from Merchants");
for(var i = 0; i < result.Count; i++)
{
Console.WriteLine(result[i].Property("Id").ToString());
}
Which does give me the exact stuff I want:
"Id": "merchants/97-A"
"Id": "merchants/98-A"
"Id": "merchants/129-A"
"Id": "merchants/130-A"
But when I transplant it backinto my form and try to add this to the datagridview I cannot see it anymore.
update: have been able to add to the list into the merchant class in the console app. Here is the code.
public void AddVenue(string idArg,Venue venue)
{
using (IDocumentSession session = store.OpenSession())
{
var merchant = session.Load<Merchant>(idArg);
List<Venue> venuesList = new List<Venue>();
if (merchant.venues == null) { session.Advanced.Patch(merchant, m => m.venues, venuesList); }
else
{
session.Advanced.Patch(merchant,
x => x.venues,
venues => venues.Add(venue));
}
session.SaveChanges();
}
}
Just so people understand what I'm talking about: here is the json that outputs from the form application:
Why?
when in console with pretty much identical code (copy pasted) I get this:
I'm getting more data from one application than the other, and I really really want the id.
I'm going to refactor the code into a wcf application I guess. Just because. Maybe I'll accidentally fix it doing that.
You can load directly the object of given class, no need to handle JSON (de)serialization yourself, unless there is a specific reason to do so.
Also, using patching is more useful when you don't want to load the document (to save bandwidth). When you already have the document loaded, you can simply change it and save the changes.
See the following code for reference:
public class Merchant
{
// note added Id property
public string Id { get; set; }
[JsonProperty(PropertyName = "name")]
public string name { get; set; }
[JsonProperty(PropertyName = "venues")]
public List<Venue> venues { get; set; }
}
public class Venue
{
[JsonProperty(PropertyName = "name")]
public string name { get; set; }
[JsonProperty(PropertyName = "tills")]
public List<Till> tills { get; set; }
}
public class Till
{
[JsonProperty(PropertyName = "name")]
public string name { get; set; }
}
public void MerchantsTest()
{
using (var store = GetDocumentStore())
{
using (var session = store.OpenSession())
{
session.Store(new Merchant { Id = "merchant-1", name = "merchant1", venues = new List<Venue> { new Venue { name = "venue-1A", tills = new List<Till> { new Till { name = "till-1A-first" } } } } });
session.Store(new Merchant { Id = "merchant-2", name = "merchant2", venues = new List<Venue> { new Venue { name = "venue-2A", tills = new List<Till> { new Till { name = "till-2A-first" } } } } });
session.SaveChanges();
}
using (var session = store.OpenSession())
{
// you can load all merchants
var merchants = session.Query<Merchant>(null, "Merchants").ToList();
// or load specific merchant by ID
var merchant2 = session.Load<Merchant>("merchant-1");
// add a venue to a loaded merchant (not using patch but simply adding the object)
merchant2.venues.Add(new Venue { name = "venue-2B", tills = new List<Till> { new Till { name = "till-2B-first" } } });
session.SaveChanges();
}
}
}
i want to call Arraylist in view. I will explain my issue clearly.
My Controller Code
public ActionResult customerid()
{
List<Customer> n = (from c in db.Customers where c.IsDeleted == false select c).ToList();
var customertype = string.Empty;
for (var i = 0; i < n.Count; i++)
{
var objCustomerName = n[i].DisplayName;
var objCustomerID = n[i].CustomerID;
var objCusCreatedDate=n[i].CreatedDate;
var objNextDate = objCusCreatedDate.GetValueOrDefault().AddDays(120);
var salescount = (from sc in db.SalesOrders where sc.CustomerID==objCustomerID && sc.CreatedDate >= objCusCreatedDate && sc.CreatedDate<= objNextDate select sc.SalesOrderID).Count();
if (salescount <= 3&& salescount> 0)
{
customertype = "Exisiting Customer";
}
else if (salescount >= 3)
{
customertype = "Potential Customer";
}
else
{
customertype = "New Customer";
}
ArrayList obj = new ArrayList();
{
obj.Add(new string[] { objCustomerName, customertype, salescount.ToString()});
}
var details = obj;
}
return View();
}
My View Model
public class CustomerTypeViewModel
{
public System.Guid CustomerID { get; set; }
public string CustomerName { get; set; }
public DateTime CreatedDate { get; set; }
public string SalesCount { get; set; }
public string CustomerType { get; set; }
}
I want to call this array list in view. How I do that? That is i am generating one view based on controller code I need output same as like which is mentioned in the below image .
Wanted Output
Wanted Output
So i put all the fields (which i going to give as a column in View) in Array list. Now i want to call that Arraylist
obj.Add(new string[] { objCustomerName, customertype, salescount.ToString()});
in view . How I do that? I tried to explain my issue as per my level best. please understand my problem and tell me one solution. I am new to MVC so please help me to solve this problem.
In your controller:
List<CustomerTypeViewModel> obj = new List<CustomerTypeViewModel>();
obj.Add(new CustomerTypeViewModel(){
CustomerName = objCustomerName,
CustomerType = customertype,
SalesCount = salescount.ToString()
});
return View(obj);
In your view
#model IEnumerable<CustomerTypeViewModel>
and display values like this
#if (Model.Any()) {
foreach (var m in Model) {
#Html.DisplayFor(x => m.CustomerName)
#Html.DisplayFor(x => m.CustomerType)
}
}
I need to get all areas that has been registered as list and all of their controllers as a sub list and the same thing for actions. something like this:
AdminArea
HomeController
Index
Add
...
OtherController
...
AnotherArea
HomeController
Index
...
...
I have checked the answer of this question, and this one, but they are not what i'm looking for.
The first one return all the routes that has been registered and the second one return all controllers at once.
Update
Ok, with the below code i can get all the areas and with the answer of the second question i can get all the controllers, but i can't figure it out each controller belong to what area.
var areaNames = RouteTable.Routes.OfType<Route>()
.Where(d => d.DataTokens != null && d.DataTokens.ContainsKey("area"))
.Select(r => r.DataTokens["area"]).ToList()
.Distinct().ToList();
So here is what i came up with, it's exactly what i wanted.
I hope it will be helpful.
public virtual ActionResult Index()
{
var list = GetSubClasses<Controller>();
// Get all controllers with their actions
var getAllcontrollers = (from item in list
let name = item.Name
where !item.Name.StartsWith("T4MVC_") // I'm using T4MVC
select new MyController()
{
Name = name.Replace("Controller", ""), Namespace = item.Namespace, MyActions = GetListOfAction(item)
}).ToList();
// Now we will get all areas that has been registered in route collection
var getAllAreas = RouteTable.Routes.OfType<Route>()
.Where(d => d.DataTokens != null && d.DataTokens.ContainsKey("area"))
.Select(
r =>
new MyArea
{
Name = r.DataTokens["area"].ToString(),
Namespace = r.DataTokens["Namespaces"] as IList<string>,
}).ToList()
.Distinct().ToList();
// Add a new area for default controllers
getAllAreas.Insert(0, new MyArea()
{
Name = "Main",
Namespace = new List<string>()
{
typeof (Web.Controllers.HomeController).Namespace
}
});
foreach (var area in getAllAreas)
{
var temp = new List<MyController>();
foreach (var item in area.Namespace)
{
temp.AddRange(getAllcontrollers.Where(x => x.Namespace == item).ToList());
}
area.MyControllers = temp;
}
return View(getAllAreas);
}
private static List<Type> GetSubClasses<T>()
{
return Assembly.GetCallingAssembly().GetTypes().Where(
type => type.IsSubclassOf(typeof(T))).ToList();
}
private IEnumerable<MyAction> GetListOfAction(Type controller)
{
var navItems = new List<MyAction>();
// Get a descriptor of this controller
ReflectedControllerDescriptor controllerDesc = new ReflectedControllerDescriptor(controller);
// Look at each action in the controller
foreach (ActionDescriptor action in controllerDesc.GetCanonicalActions())
{
bool validAction = true;
bool isHttpPost = false;
// Get any attributes (filters) on the action
object[] attributes = action.GetCustomAttributes(false);
// Look at each attribute
foreach (object filter in attributes)
{
// Can we navigate to the action?
if (filter is ChildActionOnlyAttribute)
{
validAction = false;
break;
}
if (filter is HttpPostAttribute)
{
isHttpPost = true;
}
}
// Add the action to the list if it's "valid"
if (validAction)
navItems.Add(new MyAction()
{
Name = action.ActionName,
IsHttpPost = isHttpPost
});
}
return navItems;
}
public class MyAction
{
public string Name { get; set; }
public bool IsHttpPost { get; set; }
}
public class MyController
{
public string Name { get; set; }
public string Namespace { get; set; }
public IEnumerable<MyAction> MyActions { get; set; }
}
public class MyArea
{
public string Name { get; set; }
public IEnumerable<string> Namespace { get; set; }
public IEnumerable<MyController> MyControllers { get; set; }
}
For getting actions, i used this answer.
If you have any better ways, please let me know.
I am trying to setup a classic "Article and Categories" scenario in Entity Framework. To do this, I have these classes:
public class RichContent : BaseIdEntity
{
public string Headline { get; set; }
public virtual List<RichContentCategory.RichContentCategory> Categories { get; set; }
public RichContent()
{
Categories = new List<RichContentCategory.RichContentCategory>();
}
}
And my categories:
public class RichContentCategory : BaseIdEntity
{
public string Name { get; set; }
public virtual List<RichContent.RichContent> RichContents { get; set; }
public RichContentCategory()
{
this.RichContents = new List<RichContent.RichContent>();
}
}
Which is setup with this:
modelBuilder.Entity<RichContent>()
.HasMany<RichContentCategory>(s => s.Categories)
.WithMany(c => c.RichContents)
.Map(cs =>
{
cs.MapLeftKey("RichContentRefId");
cs.MapRightKey("RichContentCategoryId");
cs.ToTable("RichContentCategoryPlacement");
});
Now, when I run this and add a category like the following and saves:
item.Categories.Add(richContentCategory);
I get the following error at _db.RichContent.Add(content); inside my CREATE method:
An unhandled exception of type 'System.InvalidOperationException' occurred in EntityFramework.dll
Additional information: An entity object cannot be referenced by multiple instances of IEntityChangeTracker.
I could understand the underlying problem is how I need to use same Context. However, I inject the context using Ninject, and my service that creates looks like this:
public class RichContentService : IRichContentService
{
private readonly Context _db;
public RichContentService(Context db)
{
_db = db;
}
public RichContent Create(RichContent content)
{
_db.RichContent.Add(content);
_db.SaveChanges();
return GetById(content.Id);
}
}
So my question is basically - how do you add categories to an article like in this case?
EDIT:
My code that runs is an importer that has this:
finally
{
if (needToCreate)
{
var result = Create(richContent);
logger.Info("Created a new rich-content page");
}
}
And the Create() method:
public RichContent Create(RichContent content)
{
PerformValidation(content);
_db.RichContent.Add(content);
_db.SaveChanges();
return GetById(content.Id);
}
And the input to the CREATE method:
var item = new RichContent()
{
WordpressId = dto.id,
DateCreated = dto.date,
Slug = dto.slug,
Content = dto.content,
Headline = dto.title,
DateModified = dto.modified,
};
if (dto.custom_fields.category_type != null && dto.custom_fields.category_type.Any() &&
!string.IsNullOrEmpty(dto.custom_fields.category_type[0]))
{
var categories = _richContentCategoryService.GetBySpecification(new RichContentCategorySpecification()
{
Take = Int32.MaxValue
});
var list = dto.custom_fields.category_type[0];
foreach (var richContentCategory in categories)
{
if (list.Contains(richContentCategory.WordpressName))
{
item.Categories.Add(richContentCategory);
}
}
}
if (dto.custom_fields.featured != null)
{
item.Featured = dto.custom_fields.featured.Any(c => c == "1");
}
if (dto.custom_fields.area != null)
{
item.Area = dto.custom_fields.area.Any(c => c == "1");
if (item.Area)
{
var children = ConvertWordpressDtos(dto.children);
foreach (var child in children.Where(c=>c.Area))
{
child.Slug = string.Format("{0}/{1}", item.Slug, child.Slug);
item.Children.Add(child);
}
}
}
The problem
The exception clearly indicates that when you save a new RichContent an entity associated with the RichContent is tracked by another Entity Framework context. In your particular case the entity is RichContentCategory that is returned from _richContentCategoryService.GetBySpecification:
var categories = _richContentCategoryService.GetBySpecification(new RichContentCategorySpecification()
{
Take = Int32.MaxValue
});
var list = dto.custom_fields.category_type[0];
foreach (var richContentCategory in categories)
{
if (list.Contains(richContentCategory.WordpressName))
{
item.Categories.Add(richContentCategory);
}
}
How to fix
The best option here is to manage to use the same context for all object that are used in this scenario. To achieve this you can add the item to categories and than use _richContentCategoryService to save categories:
var categories = _richContentCategoryService.GetBySpecification(new RichContentCategorySpecification()
{
Take = Int32.MaxValue
});
var list = dto.custom_fields.category_type[0];
foreach (var richContentCategory in categories)
{
if (list.Contains(richContentCategory.WordpressName))
{
richContentCategory.RichContents.Add(item);
}
}
// Save updated categories somehow, using "_richContentCategoryService" object
_richContentCategoryService.Save(categories);
If you are not able to do it you can try doing smth like this:
foreach (var richContentCategory in categories)
{
if (list.Contains(richContentCategory.WordpressName))
{
item.Categories.Add(new RichContentCategory { Id = richContentCategory.Id});
}
}