Creating Webservice with webmatrix - asp.net

this time i learn how to create webservice with webmatrix.
I try learn from this link :
http://www.microsoft.com/web/post/creating-a-webservice-with-webmatrix-and-consuming-it-with-a-windows-7-phone-application
but i stuck because author didn't sample source code.
This is my getproduct.cshtml code :
#{
public class Product {
public string Name {get; set; }
public int Price {get; set; }
}
public static Product GetProducts(string price) {
var db = Database.Open("WebService");
var selectQueryString = "SELECT Name, Score FROM Users WHERE Score >= " + #price;
var data = db.Query(selectQueryString);
Product product = new Product();
foreach (var row in data) {
product.Name = #row.Name;
product.Price = #row.Score;
}
return product;
}
}
This is my jsonRequest.cshtml code :
#{
var price = Request.QueryString["price"];
if (price == null || price == string.Empty) {
<p>Please enter a Price value</p>
} else {
var product = getproduct.GetProducts(price);
Json.Write(product, Response.Output);
}
}
okay and last i run http://localhost:55278/jsonRequest.cshtml, but there are two error for me, that are :
1. that address there is no QueryString, and code just past if to else.
2. error in getproductGetProduct(price);
CS0117: 'ASP.getproduct' does not contain a definition for
'GetProduct'
please help me, how to solve my problem, so that i can finish that tutorial from that link.
thank you
---UPDATE----
this is my folder
Test Webservice
|-jsonRequest.cshtml
|-App_Code
|-getproduct.cshtml

The first issue I can see is just one of case-sensitivity:
var product = getproduct.GetProduct(price);
Should be:
var product = getProduct.GetProduct(price);
The object name is case-sensitive and must be exactly the same as the name of the .cshtml file in the App_Code folder.
You seem to have edited your question to show that the case was correct originally, so the next problem I see is in the name of your method being plural. Your method signature is:
public static Product GetProducts(string price)
So you need to change:
var product = getproduct.GetProduct(price);
To:
var product = getproduct.GetProducts(price);
In your getproduct.cshtml you need to change the opening of the block from #{ to #functions {.
I know you're only following a tutorial too so this is just an aside, but that code looks absolutely ripe for an SQL injection hack to me.

Related

Dapper question. Getting values from returned object

Just started learning Dapper. I have an ADO.NET background. Using a demo I downloaded, I can insert/delete data from a webform into a MySql table just fine. This, however, I have searched all morning on.
In retrieving a single row from the db by ID, it doesn't return a LIST<>, it seems to be just an object (using code from the demo I downloaded). The query works, I get the object back. It has the fields: "ProductID, Description and Price".
The only way I could get the values to those three fields was like this:
System.Reflection.PropertyInfo pi = Product.GetType().GetProperty("ProductID");
System.Reflection.PropertyInfo desc = Product.GetType().GetProperty("Description");
System.Reflection.PropertyInfo price = Product.GetType().GetProperty("Price");
int _ProductID = (int)(pi.GetValue(Product, null));
string _Description = (string)(desc.GetValue(Product, null));
decimal _Price = (decimal)(price.GetValue(Product, null));
This works and gets the correct values for the three fields.
I'm used to looping through DataTables, but I just think there is probably a better way to get those values.
Is this the correct way to do this or am I missing something? I did actually read documentation and mess with this all morning before asking, too.
Some of the things I looked at seem to be very complex. I thought Dapper was supposed to simplify things.
OK, Thanks Marc. It was difficult for me to see what was supposed to be in the Dapper class files and what was supposed to be in my code behind. The original demo way of getting a product by ID had the query as .FirstOrDefault();
I changed everything to return a List<> and it all worked. I'm sure my ADO.NET is showing, but this works. In Dapper class files:
public List<Product> ProductAsList(int Id)
{
return this._db.Query<Product>("SELECT * FROM Cart_product WHERE ProductID=#Id", new { Id = Id }).**ToList()**;
}
This is just getting one row that matched the ProductID.
In page codebehind:
protected void CartItemAdd(string ProductId) // passing it the selected ProductID
{
var results = cartservice.ProductAsList(Convert.ToInt32(ProductId));
// returns that one row using Dapper ProductAsList(ProductId)
int _ProductId = 0;
string Description = string.Empty;
decimal Price = 0;
// Loop through the list and get the value of each item:
foreach (Product obj in results)
{
_ProductId = obj.ProductID;
Description = obj.Description;
Price = obj.Price;
}
// Using Dapper to insert the selected product into the shopping cart (table):
String UserName = "jbanks";
cartitem = new CartItem();
cartitem.ProductID = _ProductId;
cartitem.Quantity = 1;
cartitem.Description = Description;
cartitem.Price = Price;
cartitem.Created = DateTime.Now;
cartitem.CreatedBy = UserName;
result = cartservice.AddCartItem(cartitem);
if (result)
{
lblMessage.Text = string.Empty;
lblMessage.Text = "Successfully added a cart item";
}
}
}
It does indeed look up the product from one table and insert a selected item into another table.
Thanks again!
The main Query<T> API returns an IEnumerable<T>, which often will be a List<T>; the AsList<T>() extension method can get it back to a list without a copy, but either way: they are just T, for whatever T you asked for. If you asked for Query<Product>, then: they should be Product instances:
var results = connection.Query<Product>(someSql, someArgs); // perhaps .AsList()
foreach (Product obj in results) { // "var obj" would be fine here too
// now just use obj.ProductID, obj.Description and obj.Price
}
If that didn't work: check that you used the <T> version of Query. There is a non-generic variant too, which returns dynamic. Frankly, you should almost always use the <T> version.
Note: I'm assuming that somewhere you have something like
class Product {
public int ProductID {get;set;}
public string Description {get;set;}
public decimal Price {get;set;}
}

How to handle multiple session variables in ASP .Net?

As a part of online shopping, I implemented a cart using Session.
I have implemented the Cart in the following manner :
Session[pname] = qty;
where pname is a string variable which holds the name of the product and I used that as the key. qty is an integer variable which holds the number of items of that particular product.
To display the cart items I simply used the following loop :
foreach(string keys in Session.Keys)
Through this I get the names of the products along with the associated quantity and using this I display the cart items. The problem arises when I also have a session for the user active on the same page.
Session["uname"] = user_name;
And while retrieving the keys using Session.Keys, the uname gets included which I don't want as I need only the product's names. Is there any way I can read the keys from Session[pname] without reading from Session["uname"]?
Instead of storing an object in session for each product and quantity, just store a single object (e.g. List) which contains all of your cart items.
Here is an example which you could tweak to meet your needs:
First, a simple object to store the data:
public class CartItem {
public string Name { get; set; }
public int Quantity { get; set; }
}
Then if you need to add an object to the cart list:
var cartItems = new List<CartItem>();
cartItems.Add(new CartItem() {
Name = "",
Quantity = 1
});
Session["Cart"] = cartItems;
//Need to fetch the cart items later on?
cartItems = (List<CartItem>)Session["Cart"];
Obviously this can be implemented differently and this was just a quick example.
You mentioned needing an easier fix than what Justin Helgerson said, so here's a couple of suggestions, but they feel a little quick and dirty. Justin's is probably the superior solution. I used a quick Console app to demonstrate this, so place your constants where they belong, and you obviously don't have to create a dictionary.
const string USERSESSION = "uname";
Dictionary<string, object> session = new Dictionary<string, object>();
session["item1"] = 2;
session["item2"] = 1;
session[USERSESSION] = "StackOverflowUser";
// print cart items - minus the user name session key
foreach (string key in session.Keys.Where(s => s != USERSESSION))
{
Console.WriteLine("Key: {0} Value: {1}", key, session[key]);
}
Alternatively, if you plan on there being more keys than just "uname", use the Linq Except method.
// build up except set
List<string> exceptKeys = new List<string>
{
USERSESSION
};
foreach (string key in session.Keys.Except(exceptKeys))
{
Console.WriteLine("Key: {0} Value: {1}", key, session[key]);
}

ASP.NET MVC 4 Custom Action filters with dynamic data

So I am building a web application that I want to sell once Im done with it. It allows the user to enter data such as their website name, meta keywords, their contact email, phone, address etc in the admin panel. I wrote a Action Filter in order to include these values in every request that I put the filter on so I didnt have to query for them every time because these values are included in the common footer throughout the site. However, I learned that if I update the database with new or different information for these values, it does not update on the web pages which im guessing is because Action Filters are configured at application start up. In the Action Filter I am using a repository pattern to query for these values. I have included the code for the action filter below. How can I have the convenience of the Action Filter but be able to update it dynamically when the data changes in the database? Thanks!
public class ViewBagActionFilter : ActionFilterAttribute,IActionFilter
{
Repositories.SettingsRepository _repo = new Repositories.SettingsRepository();
void IActionFilter.OnActionExecuted(ActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
}
void IActionFilter.OnActionExecuting(ActionExecutingContext filterContext)
{
string siteName = _repo.GetSiteName();
string siteDesc = _repo.GetSiteDescription();
string siteKeywords = _repo.GetSiteKeywords();
string googleAnalytics = _repo.GetGoogleAnalytics();
string streetAddress = _repo.GetStreetAddress();
string zipCode = _repo.GetZipCode();
string city = _repo.GetCity();
string state = _repo.GetState();
string aboutUs = _repo.GetAboutUs();
string phone = _repo.GetPhoneNumber();
string contactEmail = _repo.GetContactEmail();
if (!string.IsNullOrWhiteSpace(siteName) && siteName.Length > 0)
{
string[] splitSiteName = new string[siteName.Length/2];
splitSiteName = siteName.Split(' ');
if (splitSiteName.Length > 1)
{
filterContext.Controller.ViewBag.SiteName1 = splitSiteName[0];
filterContext.Controller.ViewBag.SiteName2 = splitSiteName[1];
}
else
{
filterContext.Controller.ViewBag.SiteName1 = splitSiteName[0];
filterContext.Controller.ViewBag.SiteName2 = "";
}
}
//Set default values for common viewbag items that are on every page using ternary syntax
filterContext.Controller.ViewBag.SiteDescription = (!string.IsNullOrWhiteSpace(siteDesc) && siteDesc.Length > 0) ? siteDesc : "";
filterContext.Controller.ViewBag.SiteKeywords = (!string.IsNullOrWhiteSpace(siteKeywords) && siteKeywords.Length > 0) ? siteKeywords : "";
filterContext.Controller.ViewBag.GoogleAnalytics = (!string.IsNullOrWhiteSpace(googleAnalytics) && googleAnalytics.Length > 0) ? googleAnalytics : "";
filterContext.Controller.ViewBag.StreetAddress = (!string.IsNullOrWhiteSpace(streetAddress) && streetAddress.Length > 0) ? streetAddress : "";
filterContext.Controller.ViewBag.ZipCode = (!string.IsNullOrWhiteSpace(zipCode) && zipCode.Length > 0) ? zipCode : "";
filterContext.Controller.ViewBag.City = (!string.IsNullOrWhiteSpace(city) && city.Length > 0) ? city : "";
filterContext.Controller.ViewBag.State = (!string.IsNullOrWhiteSpace(state) && state.Length > 0) ? state : "";
filterContext.Controller.ViewBag.AboutUs = (!string.IsNullOrWhiteSpace(aboutUs) && aboutUs.Length > 0) ? aboutUs : "";
filterContext.Controller.ViewBag.PhoneNumber = (!string.IsNullOrWhiteSpace(phone) && phone.Length > 0) ? phone : "";
filterContext.Controller.ViewBag.ContactEmail = (!string.IsNullOrWhiteSpace(contactEmail) && contactEmail.Length > 0) ? contactEmail : "";
base.OnActionExecuting(filterContext);
}
}
I will try to explain how action filters works.
So if you extend Action filter you can override 4 base methods :
OnActionExecuting – This method is called before a controller action is executed.
OnActionExecuted – This method is called after a controller action is executed.
OnResultExecuting – This method is called before a controller action result is executed.
OnResultExecuted – This method is called after a controller action result is executed.
So thats mean that you method will be called each time before Controller will run action.
Now about optimization. You have
string siteName = _repo.GetSiteName();
string siteDesc = _repo.GetSiteDescription();
string siteKeywords = _repo.GetSiteKeywords();
string googleAnalytics = _repo.GetGoogleAnalytics();
string streetAddress = _repo.GetStreetAddress();
string zipCode = _repo.GetZipCode();
string city = _repo.GetCity();
string state = _repo.GetState();
string aboutUs = _repo.GetAboutUs();
string phone = _repo.GetPhoneNumber();
string contactEmail = _repo.GetContactEmail();
I would suggest you to create one class
public class Site{
public string SiteName{get;set;}
public string City{get;set;}
//And so on just to add all properties
}
then in repository add one more method
_repo.GetSite(); //Which will return object Site
Then
filterContext.Controller.ViewBag.CurrentSite = _repo.GetSite();
And now probably the most important for you. Why it doesnot work as you want and its a bit simple. Attribute class is initialized only once on Application start and after that it doesnot reloads, and your implementation is a bit strange since
Repositories.SettingsRepository _repo = new Repositories.SettingsRepository();
I suppose here you are loading settings. So after you load you did not reload it anymore... thats mean you will get same result each time you reload page, but if you restart iis for instance you will refresh data.
Possible solution
Move initialization of _repo to OnActionExecuting then it will reload data each time, or rewrite repository as i suggested and
filterContext.Controller.ViewBag.CurrentSite = _repo.GetSite();
Should always load new data from db.
Hope it helps :)

Import two or multiple class models to a single controller on ASP.NET

I'm very new to ASP.NET, but I know a little programming in Java. I want to use a ZIP code to query a database which will return a string, then use that string to query another database. I wanted to do this on the same control model. I thought it would be easy, and it sounds pretty easy.
When I created the controller, I put the model class of the first database, and, so far, I've gotten as far as querying the first database, but now that I have the string I want to query a second database through the DBEntities.
This displays an error saying:
> The model item passed into the dictionary is of type
> 'System.Collections.Generic.List`1[FinalBallot.Models.AgainCandidate]',
> but this dictionary requires a model item of type
> 'System.Collections.Generic.IEnumerable`1[FinalBallot.Models.ZipTable]'.
Is there a way to solve this in an easy way?
public class Default1Controller : Controller
{
private CandidatesDBEntities db = new CandidatesDBEntities();
public string districString = "";
//
// GET: /Default1/
public ViewResult Index(string searchString)
{
var queryZip = from s in db.ZipTables select s;
var queryCandidates = from s1 in db.AgainCandidates select s1;
double sT = 0;
//method so it doesnt display the whole db
if (String.IsNullOrEmpty(searchString))
{
queryZip = queryZip.Where(s => s.ZipL.Equals(0));
}
if (!String.IsNullOrEmpty(searchString))
{
sT = double.Parse(searchString);
queryZip = queryZip.Where(s => s.ZipL.Equals(sT));
try
{
districString = queryZip.ToList().ElementAt(0).District;
}
catch
{
}
if (!String.IsNullOrEmpty(districString))
{
queryCandidates = queryCandidates.Where(s1 => s1.District.Equals(districString));
}
}
return View(queryCandidates.ToList());
}
In your view, did you specify the model to be IEnumerable<ZipTable>? The model that you're passing to your view is IEnumerable<AgainCandidate>, so you would get an error if you specified your model as something else. You'd need to change the model in your view to be IEnumerable<AgainCandidate>.
UPDATE:
Based on your revised explanation, you can do a couple things:
1) create a "ViewModel" that has two properties for each of your collections you want to display on the page like so:
public class MyViewModel
{
IEnumerable<ZipTable> Zips { get; set; }
IEnumerable<AgainCandidate> Candidates { get; set; }
}
Instantiate that in your action method and return that as your model. This would be my preferred approach.
2) Stash your two collections in the ViewData bag in your action method:
ViewData["Zips"] = queryZip.ToList();
ViewData["Candidates"] = queryCandidates.ToList();
return View(ViewData);
You can pull this data in your view like this:
#foreach (var zip in ViewData["Zips"] as IEnumerable<ZipTable>)
{
...
}

MVC3 C#4.0 / Passing variables between views

new to C# and MVC. What I would like to achieve is passing a variable as ViewData from one view to another view without using ID in the ActionResult because this view generates it own variable. I am sure there are better ways to do that, but here what I thought might work.
First I made a model:
public class EventToShow
{
public Int64? ID { get; set; }
public Int64? EventID { get; set; }
}
Then I passed the variable EventID from the first View (Telerik MVC GRID) using the following:
columns.Template(item => Html.Raw(string.Format("{1}", Url.Action("tableread", "Home", new { id = (long)item.Event_ID }), "EventID"))).Width(20);
It worked using the following in my controller:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult tableread1(long? id)
{
ViewData["EID"] = id;
EventToShow ctx = new EventToShow();
ctx.ID = 1;
ctx.EventID = (long)ViewData["EID"];
return RedirectToAction("EditServerSide");
}
To pass the variable to the other view I tried to use the following (I think it is very wrong):
public ActionResult EditServerSide()
{
EventToShow ctx = new EventToShow();
var model1 = ctx.(x => x.ID == 1); **// The error here is (Identifier** expected)
ViewData["EID"] = ctx.EventID;
var model = from o in new Main().OffLinePayments
select new EditOffLinePayment
{
ID = o.ID,
Amount = o.Amount,
Details = o.Details
};
return View(model, ViewData["EID"]) **(this must be wrong)**
}
I thought maybe I should make the variable like this:
private string GetFullName()
{
EventToShow ctx = new EventToShow();
var name = EventToShow().Where(x => x.ID == 1);
ViewData["EID"] = ctx.EventID;
return name;
}
First I got an error: ‘GridEdit_OfflinePayment.Models.EventToShow' is a 'type' but is used like a 'variable'
I also did not know how to incorporate returned [name] in the EditServerSide Action.
My question, is there a better way to achieve what I am trying to do, and if this approach is correct, I would appreciate any help to fix these errors
From what I understand of the question is that you would like to pass data between several Actions? Like some sort of wizard steps process where you can pass data between multiple Actions?
If that's the case then here are some related questions and their answers:
How do I pass data across ActionResults in MVC 3?
multi-step registration process issues in asp.net mvc (splitted viewmodels, single model)

Resources