AutoCompleteExtender in ASP.NET additional info - asp.net

how do I pass additional information to the service method returning the collection of items? I'll attempt to explain what I mean, I have 2 text boxes on a form, I need to fill out names, based of a specific account id in a database. so, I need to pass an integer to the getNamesForDropDown method. I couldn't figure out what to do, so I did the wrong thing, and used the CompletionSetCount to actually pass the information I needed:
[System.Web.Services.WebMethod]
[System.Web.Script.Services.ScriptMethod]
public string[] getNamesForDropDown(string prefixText, int count)
{
String sql = "Select fldName From idAccountReps Where idAccount = " + count.ToString();
//... rest of the method removed, this should be enough code to understand
//... the evil wrongness I did.
}
in my front side aspx file, i set the CompletionSetCount based off the Account id the user is currently viewing on that page.
<ajaxtk:AutoCompleteExtender
runat="server"
ID="AC1"
TargetControlID="txtAccName"
ServiceMethod="getNamesForDropDown"
ServicePath="AccountInfo.asmx"
MinimumPrefixLength="1"
EnableCaching="true"
CompletionSetCount='<%# Eval("idAccount") %>'
/>
So, that's definitely a wrong way... what would be the right way?

azam has the right idea- but the signature of the autocomplete method can also have a third parameter:
public string[] yourmethod(string prefixText, int count, string contextKey)
you can Split up the results of the contextKey string using Azam's method- but this way you do not have to worry about sanatizing the user's input of the .Split()'s delimiter (:)

Holy smoke, I think this is what I need, I swear I never saw this option before I started programming this. Is this a new property to the autocompleteextender?
Excerpt from Documentation:
ContextKey - User/page specific context provided to an optional overload of the web method described by ServiceMethod/ServicePath. If the context key is used, it should have the same signature with an additional parameter named contextKey of type string:
[System.Web.Services.WebMethod]
[System.Web.Script.Services.ScriptMethod]
public string[] GetCompletionList(
string prefixText, int count, string contextKey) { ... }
Note that you can replace "GetCompletionList" with a name of your choice, but the return type and parameter name and type must exactly match, including case.
Edit: It doesn't matter if it is new or not, or whether i just completely overlooked it. It works, and I'm happy. It took me about 10 minutes from being confused to figuring out my own answer.

If you like you can use a separator with the prefixText. So, you can pass "1:bcd" and on the service end you can split the two items:
string[] arguments = prefixText.Split(':');
int id = Int32.Parse(arguments[0]);
string text = arguments[1];

Refer here
http://www.aspsnippets.com/Articles/ASPNet-AJAX-AutoCompleteExtender-Pass-Additional-Parameter-to-WebMethod-using-ContextKey.aspx

Related

Logical Thinking: Using Dynamic vs Static Values to Represent Data

I don't think I am asking the question correctly, but hopefully you know what I am asking.
What are pros and cons of using a string value to represent a database field (or any variable) vs using an enumeration or constant? I am not asking about the datatype, but hows its handled on the back-end. I'll use LINQ to SQL for an example.
My thinking is that by using an enumerable or constant it's: easier to read, ensures compatibly should the values ever need to be changed, and the value is hard coded -so to speak- so there are less chances of an error caused by a typo. On the flip side, do I really need a class/structure with member enumerations that essentially act as a look up for the value I want?
Using an Constant
Module Trip
Public Const OPEN As String = "Open"
Public Const PENDING_PAYMENT As String = "Pending Payment"
Public Const CANCELLED As String = "Cancelled"
Public Const CLOSED As String = "Closed"
End Module
Dim product = From p In db.Payments
Where p.PaymentId = PaymentId
For Each item In product
item.Status = PayStatus.PENDING_PAYMENT
Next
Using a string
Dim product = From p In db.Payments
Where p.PaymentId = PaymentId
For Each item In product
item.Status = "Pending Payment"
Next
As one of the comments says, the common way to deal with this is using a lookup table in the database. In its most simple form, you would have a class, let's say PaymentStatus:
Class PaymentStatus
Public Property Id As Integer
Public Property Name As String
End Class
and Payment would have reference property like
Public Property PaymentStatus As PaymentStatus
This way, you can always get the options from the database and you will never make a typo in code. It's also much easier to add options or to change descriptions.
For instance, think of what you need to do if you'd decide that "Cancelled" needs to be differentiated into "Cancelled by user" (the old status) and "Cancelled by system" (a new status introduced by new business logic). You'd need a script to update all records in the database to the new string (and change the code, but you'd be changing code anyway). A lookup table allows you to update only one record (and add a new one in this example).

How do QueryString parameters get bound to Action method parameters?

I have a webforms project, and am attempting to run some code that allows me to make a call to an MVC route and then render the result within the body of the web forms page.
There are a couple of HttpResponse/Request/Context wrappers which I use to execute a call to an MVC route, e.g.:
private static string RenderInternal(string path)
{
var responseWriter = new StringWriter();
var mvcResponse = new MvcPlayerHttpResponseWrapper(responseWriter, PageRenderer.CurrentPageId);
var mvcRequest = new MvcPlayerHttpRequestWrapper(Request, path);
var mvcContext = new MvcPlayerHttpContextWrapper(Context, mvcResponse, mvcRequest);
lock (HttpContext.Current)
{
new MvcHttpHandlerWrapper().PublicProcessRequest(mvcContext);
}
...
The code works fine for executing simple MVC routes, for e.g. "/Home/Index". But I can't specify any query string parameters (e.g. "/Home/Index?foo=bar") as they simply get ignored. I have tried to set the QueryString directly within the RequestWrapper instance, like so:
public class MvcPlayerHttpRequestWrapper : HttpRequestWrapper
{
private readonly string _path;
private readonly NameValueCollection query = new NameValueCollection();
public MvcPlayerHttpRequestWrapper(HttpRequest httpRequest, string path)
: base(httpRequest)
{
var parts = path.Split('?');
if (parts.Length > 1)
{
query = ExtractQueryString(parts[1]);
}
_path = parts[0];
}
public override string Path
{
get
{
return _path;
}
}
public override NameValueCollection QueryString
{
get
{
return query;
}
}
...
When debugging I can see the correct values are in the "request.QueryString", but the values never get bound to the method parameter.
Does anyone know how QueryString values are used and bound from an http request to an MVC controller action?
It seems like the handling of the QueryString value is more complex than I anticipated. I have a limited knowledge of the internals of the MVC Request pipeline.
I have been trying to research the internals myself and will continue to do so. If I find anything I will update this post appropriately.
I have also created a very simple web forms project containing only the code needed to produce this problem and have shared it via dropbox: https://www.dropbox.com/s/vi6erzw24813zq1/StackMvcGetQuestion.zip
The project simply contains one Default.aspx page, a Controller, and the MvcWrapper class used to render out the result of an MVC path. If you look at the Default.aspx.cs you will see a route path containing a querystring parameter is passed in, but it never binds against the parameter on the action.
As a quick reference, here are some extracts from that web project.
The controller:
public class HomeController : Controller
{
public ActionResult Index(string foo)
{
return Content(string.Format("<p>foo = {0}</p>", foo));
}
}
The Default.aspx page:
protected void Page_Load(object sender, EventArgs e)
{
string path = "/Home/Index?foo=baz";
divMvcOutput.InnerHtml = MvcWrapper.MvcPlayerFunctions.Render(path);
}
I have been struggling with this for quite a while now, so would appreciate any advice in any form. :)
MVC framework will try to fill the values of the parameters of the action method from the query string (and other available data such as posted form fields, etc.), that part you got right. The part you missed is that it does so by matching the name of the parameter with the value names passed in. So if you have a method MyMethod in Controller MyController with the signature:
public ActionResult MyMethod(string Path)
{
//Some code goes here
}
The query string (or one of the other sources of variables) must contain a variable named "Path" for the framework to be able to detect it. The query string should be /MyController/MyMethod?Path=Baz
Ok. This was a long debugging session :) and this will be a long response, so bear with me :)
First how MVC works. When you call an action method with input parameters, the framework will call a class called "DefaultModelBinder" that will try and provide a value for each basic type (int, long, etc.) and instance of complex types (objects). This model binder will depend on something called the ValueProvider collection to look for variable names in query string, submitted forms, etc. One of the ValueProviders that interests us the most is the QueryStringValueProvider. As you can guess, it gets the variables defined in the query string. Deep inside the framework, this class calls HttpContext.Current to retrieve the values of the query string instead of relying on the ones being passed to it. In your setup this is causing it to see the original request with localhost:xxxx/Default.aspx as the underlying request causing it to see an empty query string. In fact inside the Action method (Bar in your case) you can get the value this.QueryString["variable"] and it will have the right value.
I modified the Player.cs file to use a web client to make a call to an MVC application running in a separate copy of VS and it worked perfectly. So I suggest you run your mvc application separately and call into it and it should work fine.

How To Put String Value in String Array ?? Code Attached (Error: Object reference not set to an instance of an object.)

i am getting error "Object reference not set to an instance of an object." my is here,
public class UserProfession
{
public UserProfession()
{
}
public System.String[] Designation
{
get;
set;
}
}
then i am using it like,
UserProfession.Designation[0] =txt_Search.Text.ToString();
Error i mentioned you hopes for your suggestions .
-Thanks
When you make an assignment to an array property, like this:
UserProfession.Designation[0] =txt_Search.Text.ToString();
what you are actually doing is calling the get section for that property... not the set. This returns the object supported the property... the whole object, and not just the index. Index lookup does not happen until after the object is returned. Once you have that object, accessing an index works in the normal way.
You get this specific exception because you have the expression UserProfession.Designation that should return a reference to an array object, but because you never initialize the array there is nothing there when you then try to find reference the 0th element. At this point the framework discovers that the array (your "object reference") is "not set to an instance of an object"... which is just a fancy way of saying it's null.
In other words, you need to have an already existing array to hold the value you want to assign. That means doing something like this:
Designation = new String[10];
public String[] Designation
{
get;
set;
}
However, notice that we never used the set section? So you can simplify that further, like this:
Designation = new String[10];
public String[] Designation {get;private set;}
This will keep client code from completely swapping an entire array out from under your object, but otherwise will provide the full functionality of an array property. If you provide your own backing store for the array, you could even get rid of the setter entirely with no loss of functionality:
private string[] _designation = new string[10];
public string[] Designation {get {return _designation;} }
But let's add one more wrinkle: your desire to assign the to array before initializing it indicates to me that you likely don't really know how big it will be up front. If that's the case, you probably want a collection of some kind instead of an array. A generic List is a convenient and very compatible replacement for an array. That would look like this:
private List<string> _designation = new List<string>();
public List<string> Designation {get {return _designation;}}
You can still access items in that list by index, just like you would with an array. The only difference you need to worry about right now is how you add new items:
UserProfession.Designation.Add(txt_Search.Text);
Also notice that I removed the .ToString() call. Since your .Text property is almost certainly already a string, calling the .ToString() method is just silly.
You will have to initialize the object, before assigning the value. The initialization should be done just once. I have initialized the array size to ten. You can have your own values here. If you want to resize dynamically, you can use ArrayList
int length = 10;
UserProfession.Designation = new System.String[length];
UserProfession.Designation[0] =txt_Search.Text.ToString();
For more information: http://msdn.microsoft.com/en-us/library/aa287601(v=vs.71).aspx
it must initialize the value before we use because, currently, it is null.
you better add the initialization code in the constructor function.

DataMember Emit Default Value

I have a .Net Web Service function that can accept one string.
That function will then serialize that string to JSON, but I only want to serialize it if it's value is not "".
I found these instructions:
http://msdn.microsoft.com/en-us/library/aa347792.aspx
[DataContract]
public class MyClass
{
[DataMember (EmitDefaultValue=false)]
public string myValue = ""
}
Unfortunatelly I can not hide the myValue from the serialization because "" is not the .Net default value for a string (how dumb is that!)
One of two option ocurred
On the web service have some kind of attribute that sets the "" to null
Have some condition on the class
I would prefer the 1st because it makes the code cleaner but an opinion would be great.
Thanks
You can explicitly set what the default value is (for the purposes of serialization) using the DefaultValueAttribute class:
[DataContract]
public class MyClass
{
[DataMember (EmitDefaultValue=false)]
[DefaultValue("")]
public string myValue = ""
}
I think you have at least a couple of options here. It's extra work but worth it.
You can encapsulate the string in a reference type. Since reference types are null if not present, that lets you know right away if a string was present or not (because the encapsulating reference type would be either non-null or null, if the string is non-empty or not.)
A final option you have is to add an extra complementary variable (perhaps a boolean) that is set on OnDeserializing/OnDeserialized/OnSerializing/OnSerialized and use this to track whether or not something was actually present on the wire. You might, for example, set this complementary variable to true only when you're actually serializing out a non-empty string and similarly

MVC 2 Model Validation messages

i have a view model with a property like this one :
[RegularExpression(#"^d\+$", ErrorMessageResourceType = typeof(Resources.Validation), ErrorMessageResourceName = "NumberValidationMsg" )]
public int? Number {get; set;}
NumberValidationMsg resource is set to "Only numbers allowed !".
but when I try to enter something like 'test' into Number field on form, ModelState displays the ErrorMessage with content similar to : "The value 'test' is not valid for Number."
can this message be turned off, customized ?
(or maybe the best solution would be just to replace int? with string )
Thank You !
If you want to accept text in the field, you need to change it to a string, and make your conversions to int according to your rules.
If your model is an int, then the only valid input will be int (or empty, if it is "int?"), and you should not try to prevent this unless there are good reasons... Moreover, I believe that you could leave the whole regular expression out, because the MVC already does that check for you implicitly (because it is an int).

Resources