ASP.NET Core 2.1 API not taking parameter - asp.net

I am trying to pass a parameter from my API, but it does not seem to be taking it. I have a lastName (eventually will be replaced with a unique id) that I want to pass, which will ultimately route to a profile view or that person.
Here is my API Controller:
public class GetInquiryController : BaseController
{
private GetInquiry manager;
public GetInquiryController(IConfiguration config) : base(config)
{
manager = new GetInquiry(config);
}
[HttpGet]
[Route("api/[controller]")]
public IEnumerable<InquiryModel> Get(string lastName)
{
return manager.GetInquiriesByUser(lastName);
}
}
And my logic for my stored procedure that gets the last name
public class GetInquiry
{
private readonly IConfiguration configuration;
public GetInquiry(IConfiguration config)
{
configuration = config;
}
public IEnumerable<InquiryModel> GetInquiriesByUser(string lastName)
{
string ApplicationDB = configuration.GetConnectionString("ApplicationDB");
List<InquiryModel> lstinquiry = new List<InquiryModel>();
using (SqlConnection con = new SqlConnection(ApplicationDB))
{
SqlCommand cmd = new SqlCommand("spGetInquiriesByUser", con);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter lastNameParameter = cmd.Parameters.Add("lastName", SqlDbType.Char, 10);
lastNameParameter.Value = lastName;
con.Open();
SqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
InquiryModel inquiry = new InquiryModel();
//inquiry.FormID = rdr["FormID"].ToString();
inquiry.firstName = rdr["firstName"].ToString();
inquiry.lastName = rdr["lastName"].ToString();
inquiry.SID = rdr["SID"].ToString();
inquiry.email = rdr["email"].ToString();
inquiry.phone = rdr["phone"].ToString();
inquiry.email = rdr["email"].ToString();
inquiry.employer = rdr["street"].ToString();
inquiry.city = rdr["city"].ToString();
inquiry.state = rdr["state"].ToString();
inquiry.zip = rdr["zip"].ToString();
inquiry.date = rdr["date"].ToString();
inquiry.comment = rdr["comment"].ToString();
lstinquiry.Add(inquiry);
}
con.Close();
}
return lstinquiry;
}
}
}
I am using VUE.js and calling my API
methods: {
editItem(lastName) {
let id = lastName
this.$http.get('http://localhost:61601/api/GetInquiry/', {
id: lastName
}),
I have tried using my logic without IEnumerable, which i didn't think will make a difference in this case.
I guess the good thing is that I am getting,
"SqlException: Procedure or function 'spGetInquiriesByUser' expects parameter '#lastName', which was not supplied"
when type my API route into the browser, but when I add the lastName to the end of my route or Postman, I get a blank page.
Hope this makes sense, please let me know if i need to provide more detail and if someone can point me into the right direction!

You need to define from where your lastName parameter should be read.
If you want to read it from the route, use FromRoute attribute
[HttpGet("{lastName}")] //api/GetInquiry/yourlastname
public IEnumerable<InquiryModel> Get([FromRoute]string lastName)
{
return manager.GetInquiriesByUser(lastName);
}
If you want to read it from the querystring, use FromQuery attribute
[HttpGet] //api/GetInquiry?lastName=yourlastname
public IEnumerable<InquiryModel> Get([FromQuery]string lastName)
{
return manager.GetInquiriesByUser(lastName);
}
Note: Above solution works when moving the [Route("api/[controller]")] ontop of the GetInquiryController class.
Update
When you added your vue.js api call it makes more sence why this is not working, you are actually calling the lastName parameter by the id name. Changing your id prop to lastName would work with above
methods: {
editItem(lastName) {
this.$http.get('http://localhost:61601/api/GetInquiry/', {
lastName: lastName
}),

Related

How to add data to associative table in asp.net core

I am new to asp.net core. I am building a web application for book management. I have a table called Author and books. Being a many to many relationships I made an associative entity that consists of the bookId and authorId. When I try to create I am able to create author and book. I successfully added the author and book to the database.
My author class looks like this
public class Author
{
private int _ID
private string _Name;
public string ID {
get { return _ID; }
set { _ID = value; }
public string Name {
get { return _Name; }
set { _Name = value; }
}
My book class is
public class Author
{
private int _ID
private string _Name;
private string _Title;
public string ID {
get { return _ID; }
set { _ID = value; }
}
public string Title {
get { return _Name; }
set { _Name = value; }
}
public string Name {
get { return _Name; }
set { _Name = value; }
}
I have a data access called db.cs to help to create the book and author in database.
public static int AddAuthor(Author A)
{
int renum = -1;
SqlConnection conn = null;
conn = new SqlConnection(ConnectionString);
conn.Open();
SqlCommand comm = new SqlCommand("sproc_AuthorAdd", conn);
comm.CommandType = System.Data.CommandType.StoredProcedure;
comm.Parameters.AddWithValue("#Name", A.Name);
comm.Parameters.AddWithValue("#Title", a.Title);
SqlParameter output = new SqlParameter();
output.ParameterName = "#AuthorID";
output.DbType = System.Data.DbType.Int32;
output.Direction = System.Data.ParameterDirection.Output;
comm.Parameters.Add(output);
int affect = comm.ExecuteNonQuery();
renum = affect;
c.ID = (int)output.Value;
I have done the same for books as well. I want to fill out the association table as well when the user filled out a book and author using their ID. I tried to do various things like using a cookie to pass data. But I cannot store data. Any kind of help is appreciated. Thanks in advance.
I'm not really sure I understand your last code snippet, but if you're having issues managing your many-to-many relationship between Books and Authors, have you considered just using Entity Framework Core?
Instead of writing a bunch of code that accesses your database, you just create models of your tables (similar to the classes you have defined above), and it handles the many-to-many relationship for you. The code to query for Authors and/or Books could then look as simple as:
using (var db = new dbContext())
{
var books = db.Books
.Where(b => b.ID > 1234)
.OrderBy(b => b.Title)
.ToList();
}
And creating a new Book or Author would be similarly simple:
using (var db = new dbContext())
{
var book = new Book { ID = 1234, Title = "Some Title", Name = "Some Name" };
db.Books.Add(book);
db.SaveChanges();
}
You might have to reimplement a bunch of things to take advantage of Entity Framework Core in your app, but it sounds like it would save you time in the long run.

How to pull through Row Version values from a SQLite in-memory database

I am currently implementing a Database collection/fixture for my unit tests, as documented on this question here:
xUnit.net - run code once before and after ALL tests
However, instead of using an InMemory Database, I'm using SQLite as InMemory currently has a bug in .Net Core 2.1 which doesn't do a sequence check when using a byte array type
Which leads me to my current predicament, namely that the byte array when you set up a database fixture doesn't get pulled through to the unit test when the context is pulled from the Database Fixture and into the unit test, which is causing concurrency errors when I try to run the tests.
As an example:
Fist set the DatabaseFixture class like so:
public class DatabaseFixture : IDisposable
{
public DatabaseFixture()
{
var connectionStringbuilder = new SqliteConnectionStringBuilder{DataSource = ":memory:", Cache = SqliteCacheMode.Shared};
var connection = new SqliteConnection(connectionStringbuilder.ToString());
options = new DbContextOptionsBuilder<CRMContext>()
.UseSqlite(connection)
.EnableSensitiveDataLogging()
.Options;
using (var context = new CRMContext(options))
{
context.Database.OpenConnection();
context.Database.EnsureCreated();
context.Persons.AddRange(persons);
context.SaveChanges();
}
}
public DbContextOptions<CRMContext> options { get; set; }
public void Dispose()
{
using (var context = new CRMContext(options))
{
context.Database.CloseConnection();
context.Dispose();
}
}
private IQueryable<Person> persons = new List<Person>()
{
new Person
{
Id = 1,
Forename = "Test",
Surname = "User",
RowVersion = new byte[0]
},
new Person
{
Id = 2,
Forename = "Another",
Surname = "Test",
RowVersion = new byte[0]
}
}.AsQueryable();
}
Setup your empty DatabaseCollection class as per the first link:
[CollectionDefinition("Database collection")]
public class DatabaseCollection : ICollectionFixture<DatabaseFixture>
{
}
Then set up your unit test to use this Database Fixture:
[Collection("Database collection")]
public class PersonTests : BaseTests
{
private readonly DatabaseFixture _fixture;
public PersonTests(DatabaseFixture fixture)
{
_fixture = fixture;
}
[Fact]
public void SaveAndReturnEntityAsync_SaveNewPerson_ReturnsTrue()
{
{
using (var context = new Context(_fixture.options))
{
var existingperson = new Person
{
Id = 2,
Forename = "Edit",
Surname = "Test",
RowVersion = new byte[0]
};
var mapperConfig = new MapperConfiguration(cfg => { cfg.AddProfile(new InitializeAutomapperProfile()); });
var AlertAcknowledgeService = GenerateService(context);
//Act
//var result = _Person.SaveAndReturnEntityAsync(mappedPersonAlertAcknowledge);
//Assert
Assert.Equal("RanToCompletion", result.Status.ToString());
Assert.True(result.IsCompletedSuccessfully);
Assert.Equal("The data is saved successfully", result.Result.SuccessMessage);
}
}
Now when I debug this, it hits the fixture correctly, and you can when you expand the Results view, the RowVersion variable is assigned correctly:
However, when the data is passed into the unit test, the row version gets set to null:
Any help on this would be greatly appreciated!

nice overload structure

I have created a library function and want to add an overload that does a very similar thing with an additional parameter. The existing code looks like this:
public class MealsAllocation
{
public int mealId;
public List<CrewSummary> crew;
private MealsAllocation() { }
public MealsAllocation(int MealId) {
mealId = MealId;
string connStr = ConfigurationManager.ConnectionStrings["LocalSqlServer"].ConnectionString;
SqlConnection conn = new SqlConnection(connStr);
//first fill an ienumerable redemption object for the meal
List<MealRedemption> mealRedemptions = new List<MealRedemption>();
SqlCommand cmdRed = new SqlCommand("tegsGetMealsRedemption", conn);
cmdRed.CommandType = CommandType.StoredProcedure;
cmdRed.Parameters.Add(new SqlParameter("#mealId", MealId));
conn.Open();
SqlDataReader drRed = cmdRed.ExecuteReader();
while (drRed.Read())
{
MealRedemption mr = new MealRedemption(Convert.ToInt32(drRed["crewId"]), Convert.ToDateTime(drRed["creation"]), Convert.ToInt32(drRed["redeemed"]));
mealRedemptions.Add(mr);
}
conn.Close();
//then fill the crew list
crew = new List<CrewSummary>();
SqlCommand cmdCrew = new SqlCommand("tegsGetMealsAllocation", conn);
cmdCrew.CommandType = CommandType.StoredProcedure;
cmdCrew.Parameters.Add(new SqlParameter("#mealId", MealId));
conn.Open();
SqlDataReader drCrew = cmdCrew.ExecuteReader();
while (drCrew.Read())
{
int drCid = Convert.ToInt32(drCrew["id"]);
List<MealRedemption> drMr = mealRedemptions.FindAll(red => red.crewId == drCid) ;
CrewSummary cs = new CrewSummary(drCid, Convert.ToInt32(drCrew["allocation"]), drMr );
crew.Add(cs);
}
conn.Close();
}
So then now I wish to add a new overload that will look a bit like this:
public MealsAllocation(int MealId, int crewId)
{
}
and essentially this will do much the same but slightly different from the above.
What would be a good strategy to avoid "copy and paste inheritance" ?
ie a nice way to refactor the above so that it lends itself more easily to the overload?
How about moving your logic to an internal function so it's only accessible in this assembly, and to this class and use optional parameters... something like this:
public class MealsAllocation
{
public int mealId;
public List<CrewSummary> crew;
private MealsAllocation()
{
}
public MealsAllocation(int MealId)
{
DoWork(MealId);
}
public MealsAllocation(int MealId, int crewId)
{
DoWork(MealId, crewId);
}
internal void DoWork(int MealId, int crewId = -1)
{
// have your logic here based on your parameter list
// valid crewId passed, then add new param for DB proc
if (crewId > -1)
{
cmdCrew.Parameters.Add(new SqlParameter("#crewId", crewId));
}
}
}
You can user object initializer
var mealRedemption = new
{
MealId = yourvlue,
Crew = crew
};
Link : http://msdn.microsoft.com/en-us/library/bb384062.aspx
Since you want to overload your constructor, you could also try such an approach:
public MealsAllocation(int MealId) : this (MealId, null)
{
}
public MealsAllocation(int MealId, int? crewId)
{
// Initialize your instance as needed
if (crewId.HasValue)
{
// Do some more stuff
}
}
Although I don't recommend doing all that inside the constructor, you can simply add an optional param to the end:
public class MealsAllocation
{
public int MealId { get; set; }
public int CrewId { get; set; }
public List<CrewSummary> Crew { get; set; };
public MealsAllocation(int mealId, int crewId = 0)
{
this.MealId = mealId;
this.CrewId = crewId;
if(this.CrewId = 0) // etc...
}
Side note: You need to add the using statement around your SqlConnection, SqlCommand and SqlDataReader object or you could run into connection and/or memory leaks. Personally, I'd create a Data Access layer and put all of the data related methods there to make them reusable across your entire business layer.
Also, I think this might be a good candidate for the Lazy<T> object: http://msdn.microsoft.com/en-us/library/dd642331.aspx
The first thing that comes to mind is to split that big chunk of code in two different methods
giving at each method a specialized functionality
public MealsAllocation(int MealId)
{
List<MealRedemption> mealRedemptions = LoadMealRedemptions(MealID);
LoadCrewSummaryByMeal(mealRedemptions, MealID);
}
while the other constructor could be
public MealsAllocation(int MealId, int crewId)
{
List<MealRedemption> mealRedemptions = LoadMealRedemptions(MealID);
LoadCrewSummaryByCrew(mealRedemptions, MealID, crewID);
}
In the first constructor you call the private method where you load the MealRedemptions list, get its output and pass to a specialized method that load the CrewSummary list using only the MealID and the list obtained from the first method.
In the second constructor you could use the same method used in the first one and then use a different one for the loading of the CrewSummary. The requirements of your second constructor are not clear and could change the design of this second method (I mean, how do you use the crewID parameter to change the inner workings to build the CrewSummary list?)

why is my query not returning 6 items?

Afternoon,
Can any one see why my query is not returning a random 6 items please?
public class GetQuestions
{
public int qId { get; set; }
public string question { get; set; }
public string answer1 { get; set; }
public string answer2 { get; set; }
public string answer3 { get; set; }
}
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public List<GetQuestions> Questions()
{
using (QuizDataContext dc = new QuizDataContext())
{
var query = from q in dc.tblquizs
orderby Guid.NewGuid()
select new GetQuestions
{
qId = q.id,
question = q.q,
answer1 = q.a1,
answer2 = q.a2,
answer3 = q.a3,
};
return query.Take(6).ToList();
}
Updated Add the GetQuestions Class
You can't get random order by using
orderby Guid.NewGuid()
You can test this by doing the following query and seeing the result:
from q in dc.tblquizs
select Guid.NewGuid()
Entity Framework 4.3.1 will translate the Guid.NewGuid() call to newid() - this would definitely be the preferred methodology if your DAL supports it. It may be, however, that whatever DAL you're using doesn't translate the call properly (in which case it may get translated to a GUID before it's sent to the database server, resulting in a static value for ordering). You should use a database profiler to see what your DAL is doing.
If the Guid.NewGuid call is not translating to newid() properly, you have two other options:
Use a sproc
Use something like the LINQ below (as a last resort)
var context = new ScratchContext();
var products = new List<Product>();
for (int i = 0; i < num; i++)
{
Product product = null;
while (product == null)
{
int randomId = r.Next(context.Products.Count());
product = context.Products.FirstOrDefault(p => p.ID == randomId);
}
products.Add(product);
}
return products.AsQueryable();
I used the following code to resolve this issue.
var qry = from q in dc.tblwhiskysprintquizs.AsEnumerable()
orderby Guid.NewGuid()
select new GetQuestions
{
qId = q.id,
question = q.q,
answer1 = q.a1,
answer2 = q.a2,
answer3 = q.a3,
};
return qry.Take(6).ToList();
It was as simple as adding .AsEnumerable to the look up.
orderby Guid.NewGuid()
generates random numbers that may not exist in your db

Datastructures problem in asp.net/c#

I have a e-commerce web application which allows users to buy software components in my website. I'm retrieving the invoice number and the software component title that was bought by the user from UserTransactionHistory table in sql server. I'm storing them in arraylist with the help of a SoftwareTitles Class
public class SoftwareTitles
{
string softwareTitle;
string invoiceNumber;
public SoftwareTitles(string softwareTitle, string invoiceNumber)
{
this.softwareTitle = softwareTitle;
this.invoiceNumber = invoiceNumber;
}
string InvoiceNumber
{
get
{
return this.invoiceNumber;
}
}
string SoftwareTitle
{
get
{
return this.softwareTitle;
}
}
}
}
And I'm adding this class to arraylist in this manner.
ConnectionToSql con1 = new ConnectionToSql();
string connectionString = con1.ConnectionStringMethod();
SqlConnection sqlConnection = new SqlConnection(connectionString);
SqlCommand cmd2 = new SqlCommand("SelectionOfSoftwareTitles", sqlConnection);
cmd2.CommandType = CommandType.StoredProcedure;
sqlConnection.Open();
SqlDataReader dr2 = cmd2.ExecuteReader();
if (dr2.HasRows)
{
while (dr2.Read())
{
String softwareTitle = (String)dr2[0];
String invoiceNumber = (String)dr2[1];
softwareTitlesArray.Add(new SoftwareTitles(softwareTitle, invoiceNumber));
int i = 0;
}
}
sqlConnection.Close();
dr2.Close();
But when I want to retrieve all the software titles that are associated with a certain Invoice number. I'm not able to do it.
Am i doing it properly ?? Is arraylist appropriate data structure for such operation ?? How should I do it ?
I would personally use a non-generic list object.
To declare:
List<Software> softwareTitles= New List<Software>();
And the object software:
if (dr.HasRows)
{
while (dr.Read())
{
string title = dr["TITLE_COLUMN"];
int invoice = dr["INVOICE_COLUMN"];
Software s = new Software();
s.Title = title;
s.Invoice = invoice;
softwareTitles.add(s);
}
}
and then you can traverse through the list using a simple loop and counter like, softwareTitles(i) or you can even use LINQ to accomplish whatever you want to do.
e.g.
for (i=0; i<softwareTitles.Count;i++)
{
if (softwareTitles[i].Invoice==213)
{
Console.WriteLine(softwareTitles[i].Title);
}
}
Somthing like that. Sorry I am using VB.NET lately, so my C# has become rusty. But it seems correct
Use Generic List Collection to add the Objects and Linq to Query the Records.

Resources