ASP.NET Passing parameter and return values - asp.net

I'm trying to understand how to properly pass a parameter and more importantly, return one or several values.
In the main method I have:
public IActionResult FinVD()
{
var user = from d in _context.Roles
join userRole in _context.UserRoles on d.Id equals userRole.RoleId
join usuario in _context.Users on userRole.UserId equals usuario.Id
where usuario.UserName == User.Identity.Name
select d;
var cargo = user.FirstOrDefault();
var cargodesc = cargo.Name;
ListaTienda(cargodesc);
//...More code
FinanzaDIndexData ventadiaria = new FinanzaDIndexData()
{
MedioPagos = medio_pago,
hechosf_periodo = fecha,
//Here lies the problem. Is not initialized in the context if the code stays like this.
HechosFinanzaL = ListaHechosFinanza,
};
return View(ventadiaria);
}
Passing this parameter to ListaTienda will do the following:
Generate a ViewBag
Generate a List
private void ListaTienda(string cargodesc)
{
if (cargodesc == "Jefe")
{
List<Tienda> ListaTienda = new List<Tienda>();
ListaTienda = _context.Stores.Where(j => j.Districts.Provincias.provincia_jefe == User.Identity.Name && j.tienda_vigencia_reg == 1).OrderBy(j => j.tienda_nombre).ToList();
ListaTienda.Insert(0, new Tienda { tienda_id = 0, tienda_nombre = "-- Seleccione Tienda --" });
ViewBag.ListaTienda = ListaTienda;
List<HechosFinanza> ListaHechosFinanza = new List<HechosFinanza>();
ListaHechosFinanza = _context.HechosFinanza.Include(f => f.Devices).ThenInclude(f => f.Machines).ThenInclude(f => f.Stores).ThenInclude(f => f.Districts).ThenInclude(f => f.Provincias)
.Where(f => f.finanzas_id == 1 &&
f.Devices.Machines.Stores.Districts.Provincias.provincia_jefe == User.Identity.Name)
.OrderBy(f => f.Devices.Machines.Stores.tienda_nombre).ToList();
//...more code
}
}
The problem:
When I go back to the main method, I have a List waiting to be populated with the result of ListaHechosFinanza but I get the message:
The name 'ListaHechosFinanza' does not exist in the actual context
Do I have to declare an empty List<HechosFinanza> in the main method, pass it as a parameter and let it be modified using ref? or without it since is a List? Like this?:
public IActionResult FinVD()
{
var user = from d in _context.Roles
join userRole in _context.UserRoles on d.Id equals userRole.RoleId
join usuario in _context.Users on userRole.UserId equals usuario.Id
where usuario.UserName == User.Identity.Name
select d;
var cargo = user.FirstOrDefault();
var cargodesc = cargo.Name;
List<HechosFinanza> ListaHechosFinanza = new List<HechosFinanza>();
ListaTienda(cargodesc, ListaHechosFinanza);
//... more code
FinanzaDIndexData ventadiaria = new FinanzaDIndexData()
{
MedioPagos = medio_pago,
hechosf_periodo = fecha,
HechosFinanzaL = ListaHechosFinanza,
};
return View(ventadiaria);
}
Part 2:
private void ListaTienda(string cargodesc, List<HechosFinanza> ListaHechosFinanza)
{
if (cargodesc == "Jefe")
{
List<Tienda> ListaTienda = new List<Tienda>();
ListaTienda = _context.Stores.Where(j => j.Districts.Provincias.provincia_jefe == User.Identity.Name && j.tienda_vigencia_reg == 1).OrderBy(j => j.tienda_nombre).ToList();
ListaTienda.Insert(0, new Tienda { tienda_id = 0, tienda_nombre = "-- Seleccione Tienda --" });
ViewBag.ListaTienda = ListaTienda;
//List<HechosFinanza> ListaHechosFinanza = new List<HechosFinanza>();
ListaHechosFinanza = _context.HechosFinanza.Include(f => f.Devices).ThenInclude(f => f.Machines).ThenInclude(f => f.Stores).ThenInclude(f => f.Districts).ThenInclude(f => f.Provincias)
.Where(f => f.finanzas_id == 1 &&
f.Devices.Machines.Stores.Districts.Provincias.provincia_jefe == User.Identity.Name)
.OrderBy(f => f.Devices.Machines.Stores.tienda_nombre).ToList();
}

ListaTienda() method needs to return a list of HechosFinanza.
So change it to
private IList<HechosFinanza> ListaTienda(string cargodesc, List<HechosFinanza> ListaHechosFinanza)
Also, since this method returns a value now, you need to assign its value to ListaHechosFinanza in FinVD() which will look like:
IList<HechosFinanza> ListaHechosFinanza = ListaTienda(cargodesc, ListaHechosFinanza);
This error message means that the variable ListaHechosFinanza is not 'visible' to the ListaTienda method as this is a local variable.
The name 'ListaHechosFinanza' does not exist in the actual context
Head over to MSDN to understand the scoping of the variables which is at the crux of data sharing and access.
Also, always code to interface, not implementation. More info here - What does it mean to "program to an interface"?

Related

How can add several fields to NEST?

I use Generic and Reflection, so the main problem is add several fields. When i use this code with one field it OK but when i try somehow add new fields it doesn't work:
public static ISearchResponse<T> PartSearch<T>(ElasticClient client, string query, List<string> fieldList = null, int from = 0, int size = 1) where T : class
{
if (client == null)
throw new ArgumentNullException();
if (String.IsNullOrEmpty(query))
throw new ArgumentNullException();
ISearchResponse<T> results;
if (fieldList == null)
{
results = client.Search<T>(q =>
q.Query(q =>
q.QueryString(qs => qs.Query(query))
).From(from).Size(size)
);
}
else
{
results = client.Search<T>(q =>
q.Query(q => q
.QueryString(qs =>
{
//This place where i try to add several fields
List<Field> fildArray = new List<Field>();
foreach (var arg in fieldList)
{
var fieldString = new Field(typeof(T).GetProperty(arg));
fildArray.Add(fieldString);
}
qs.Fields(f => f.Field(fildArray));
qs.Query(query);
return qs;
})
).From(from).Size(size)
);
}
return results;
}
I created an example using Lenient() that can help you with your question:
https://github.com/hgmauri/elasticsearch-with-nest/blob/master/src/Sample.Elasticsearch.Domain/Abstractions/NestExtensions.cs
Problem was in one QueryString parameter Lenient:
https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html
Fixed this by setting it on True.

Unit Test not passed, since not seen any return from api controller

I have an API as below:
private readonly IMyService _myService;
public MyController(IMyService myService)
{
_myService = myService;
}
//GET: api/values
[HttpGet]
public MyOutput<MyEntity> Get(string f, string o)
{
var fItems = JsonConvert.DeserializeObject<Dictionary<string, string>>(f);
var oItems = GetDictionaryFromStr(o ?? "");
var myInput = new MyInput<MyEntity>()
{
PredicateDictionary = fItems,
OrderByDictionary = oItems
};
var result = _myService.Search(myInput);
return result;
}
It works well. Now, I want to write a unit test for my API, using Moq and Xunit;. I want to set the expected values of result, then mock my DIs and call the controller, What I expect is that the return value of controller and my results be equal. but I don't know why result in var result = api.Get(f, o); is null after returns from controller. Is there anything wrong whit my test?
[Fact]
public void Should_ReturnResult_When_CallingMyApi()
{
//Arrange
var f = "{'Currency':'UR'}";
var o = "+Amount";
var fItems = JsonConvert.DeserializeObject<Dictionary<string, string>>(f);
var oItems = GetDictionaryFromStr(o ?? "");
var baseServiceMock = new Mock<IMyService>();
baseServiceMock
.Setup(x => x.Serach(It.Is<MyInput<MyEntity>>
(i => i.PredicateDictionary== fItems
&& i.OrderByDictionary == oItems
&& i.Paging == pagingItems
)))
.Returns(new MyOutput<MyEntity>()
{
OrderByDictionary = oItems,
PredicateDictionary = fItems
});
var api = new MyController(baseServiceMock.Object);
//Act
var result = api.Get(f, o);
////Assert
Assert.Equal(result.PredicateDictionary, fItems);
Assert.Equal(result.OrderByDictionary, oItems);
}
Update:
Also I changed the baseServiceMock, with and without the It.Is. In case of It.Is I added
baseServiceMock
.Setup(x => x.Search(It.Is<MuInput<MyEntity>>
(i => i.PredicateDictionary.Keys == fItems.Keys
&& i.PredicateDictionary.Values == fItems.Values
&& i.OrderByDictionary.Keys == oItems.Keys
&& i.OrderByDictionary.Values == oItems.Values
&& i.Paging == pagingItems
)))
.Returns.....
The problem was comparing two objects in SetUp(). So I Edited the code as below:
.Setup(x => x.Find(It.Is<MuInput<MyEntity>>
(i => i.PredicateDictionary.First().Key == "Currency"
&& i.PredicateDictionary.First().Value == "CU_UR"
&& i.OrderByDictionary.First().Key == "Amount"
&& i.OrderByDictionary.First().Value == "Asc")))

Pass ViewBag with List to view for foreach loop

I am passing a query result from the controller to a view through a Viewbag but when looping through the Viewbag result I get the error 'object' does not contain a definition for 'Ratings' even though it does show up when debugging. I am not using a model for the query so I cannot cast the list.
How do I send through the list from the query or the query results itself to the view to so I loop through and extract the data?
Controller
var AppQuery = (from ans in db.Answers
join ques in db.Questions on ans.QuestionID equals ques.QuestionID
join resp in db.Responses on ans.ResponseID equals resp.ResponseID
join sec in db.Sections on ques.SectionID equals sec.SectionID
where resp.ResponseID == ID && ques.SubSectionName != null
select new { SectionName = sec.SectionName, RatingAnswer = ans.RatingAnswer })
.GroupBy(a => a.SectionName)
.Select(a => new { SectionName = a.Key, Ratings = a.Sum(s => s.RatingAnswer) });
ViewBag.Results = AppQuery.ToList();
View
#{var Results = ViewBag.Results;}
#foreach (var item in Results)
{
var style = "active";
var condition = "";
if (item.Ratings >= 90)
{
style = "success";
condition = "Excellent";
}
else if (item.Ratings < 50)
{
style = "danger";
condition = "Critical";
}
else
{
style = "active";
condition = "Stable";
}
<tr class="#style">
<td>#item.SectionName</td>
<td>#item.Ratings</td>
<td>#condition</td>
</tr>
}
Thanks for the help!
This is the expected behaviour!. Because you set a collection of anonymous objects to your ViewBag.
You should be using a strongly typed view model.
public class RatingVm
{
public string SectionName { set;get;}
public int Ratings { set;get;}
}
and in your action method,
public ActionResult Create()
{
var results= (from ans in db.Answers
join ques in db.Questions on ans.QuestionID equals ques.QuestionID
join resp in db.Responses on ans.ResponseID equals resp.ResponseID
join sec in db.Sections on ques.SectionID equals sec.SectionID
where resp.ResponseID == ID && ques.SubSectionName != null
select new { SectionName = sec.SectionName,
RatingAnswer = ans.RatingAnswer })
.GroupBy(a => a.SectionName)
.Select(a => new RatingVm { SectionName = a.Key,
Ratings = a.Sum(s => s.RatingAnswer) }).ToList();
return View(results);
}
Now your view should be strongly typed to the type of data we are passing from our action method, which is a collection of RatingVm
#model List<RatingVm>
<h1>Ratings</h1>
#foreach(var item in Model)
{
<p>#item.SectionName</p>
<p>#item.Ratings</p>
}

Cannot implicitly convert type 'System.Collections.Generic.List<AnonymousType#1>' to 'System.Collections.Generic.List<DAL.HRM_PersonalInformations>'

I am trying to Get some data from Database and Bind them in Drop-Down list.. But getting following error : -
public virtual List<HRM_PersonalInformations>GetAssignePerson(String OCODE, int dptID){
var query = (context.HRM_PersonalInformations.Where
(c => c.OCODE == OCODE && c.DepartmentId == dptID)
.Select(c => new {FullName = (c.FirstName + ' ' + c.LastName), c.EID})).ToList();
return query; // It indicate error line
}
After that I am trying to Bind data in dropdown list and my code is following : -
private void FillAssignPerson()
{
try
{
string OCODE = ((SessionUser)Session["SessionUser"]).OCode;
int dptId = Convert.ToInt32(ddlAssignPerDept.SelectedValue);
var row = enquiryBll.GetAssignePerson(OCODE, dptId).ToList();
//const string list = "SELECT FirstName + ' ' + LastName AS FullName, EID, FirstName, LastName " +
// "FROM HRM_PersonalInformations " +
// "ORDER BY EID ASC"
if (row.Count > 0)
{
ddlAssignPerson.Items.Clear();
ddlAssignPerson.DataSource = row;
ddlAssignPerson.DataTextField = "FullName";
ddlAssignPerson.DataValueField = "EID";
ddlAssignPerson.DataBind();
ddlAssignPerson.Items.Insert(0, new ListItem("----- Select One -----", "0"));
ddlAssignPerson.AppendDataBoundItems = false;
}
}
Is it right way ?? Can anyone help me ? Thanks for Advance ..
Well, in your projection you have:
c => new {FullName = (c.FirstName + ' ' + c.LastName), c.EID}
That's creating an instance of an anonymous typoe - not an instance of HRM_PersonalInformations. If those are the only two properties you need in HRM_PersonalInformations, you could just change it to:
c => new HRM_PersonalInformations {
FullName = (c.FirstName + ' ' + c.LastName),
EID = c.EID
}
Or judging by your query, you may not need a projection at all. You may be fine with:
return context.HRM_PersonalInformations
.Where(c => c.OCODE == OCODE && c.DepartmentId == dptID)
.ToList();
Alternatively, if you only need those properties and don't really need the items of your list to be instances of HRM_PersonalInformations, you could just change the method's signature to be:
public virtual IList GetAssignePerson(...)
and keep the body as it is. You can't explicitly write a method declaration which specifies the anonymous type, because it doesn't have a name - but List<T> implements IList, so the above will certainly compile... it will fail if you later try to cast an element in it to HRM_PersonalInformations though.
EDIT: If the string concatenation is a problem, you might need to do that client-side. For example:
public IList GetAssignePerson(String OCODE, int dptID) {
return context.HRM_PersonalInformations
.Where(c => c.OCODE == OCODE && c.DepartmentId == dptID)
.Select(c => new { c.FirstName, c.LastName, c.EID })
.AsEnumerable() // Do the rest client-side
.Select(c => new {
FullName = c.FirstName + " " + c.LastName,
c.EID
})
.ToList();
}
This methods awaits you HRM_PersonalInformations , why are you return anonymous type ?
It is useful to go back to the expected type
Try this code
.Select(c => new HRM_PersonalInformations()
{
FullName = c.FirstName
// set other prop
});
this is a simple sample,
If you want to customize data business process or UI process you need a new model for example You want to display full name in Dropdown so ,
Add new folder MyCustomizeModels
Add new class DropdownLookUpDecimal in MyCustomizeModels
this DropdownLookUpDecimal class.
public class DropdownLookUpDecimal
{
public decimal Value { get; set; }
public string Text { get; set; }
}
You can use this class all Dropdown in the project.
public List<DropdownLookUpDecimal>GetAssignePerson(string oCode, int dptID)
{
var query = context.HRM_PersonalInformations.Where
(c => c.OCODE == oCode&& c.DepartmentId == dptID)
.Select(c => new DropdownLookUpDecimal
{
Text = c.FirstName + ' ' + c.LastName,
Value = c.EID
});
return query.ToList();
}
Just create new .cs and fill the list with the class and return List.
I hope it helped

Values returned from my Repository model class is being cached

I have the following Post Edit action method:-
[HttpPost]
[ValidateAntiForgeryToken]
[CheckUserPermissions(Action = "Edit", Model = "StorageDevice")]
public ActionResult Edit(SDJoin sdj, FormCollection formValues)
{
//code goes here
if (ModelState.IsValid)
{
repository.Save();
catch (DbUpdateConcurrencyException ex)
{
var entry = ex.Entries.Single();
var databaseValues = (TMSStorageDevice)entry.GetDatabaseValues().ToObject();
var clientValues = (TMSStorageDevice)entry.Entity;
var databaseTechnology2 = repository.FindTechnology2(sdj.StorageDevice.TMSStorageDeviceID);
if (sdj.NetworkInfo.IPAddress != databaseTechnology2.TechnologyIPs.SingleOrDefault(a=>a.IsPrimary == true).IPAddress )
ModelState.AddModelError("NetworkInfo.IPAddress", "Value Has Changed "
);
if (sdj.NetworkInfo.MACAddress != databaseTechnology2.TechnologyIPs.SingleOrDefault(a => a.IsPrimary == true).MACAddress)
ModelState.AddModelError("NetworkInfo.MACAddress", "Value Has Changed "
);
if (databaseValues.RackID != clientValues.RackID)
ModelState.AddModelError("StorageDevice.RackID", "Value Has Changed "
);
But currently the values returned from the
var databaseTechnology2 = repository.FindTechnology2(sdj.StorageDevice.TMSStorageDeviceID);
will return a cached value inside the server , instead of retrieving the current database value. The repository method is :-
public Technology FindTechnology2(int id)
{
return tms.Technologies.Include(a=>a.TechnologyIPs).SingleOrDefault(a => a.TechnologyID == id);
}
Can anyone advice ?
I'm posting this as a follow up to my comment in order to show code properly.
You can set MergeOptions.OverwriteChanges as follows:
var objectContext = ((IObjectContextAdapter)entities).ObjectContext; //assuming 'entities' is your context here
var set = objectContext.CreateObjectSet<TechnologyRoles>();
set.MergeOption = MergeOption.OverwriteChanges;
var query = set.SingleOrDefault(a => a.TechnologyID == id);
Hope this helps,

Resources