Ajax in asp web forms doesn't get called - asp.net

I have many buttons and when the user clicks on one, I want it to update a label with ajax.
I implemented ajax in my template like so:
<form runat="server">
<asp:ScriptManager ID="ScriptManagerPull" runat="server">
</asp:ScriptManager>
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<div runat="server" id="SiteContent">
</div>
</ContentTemplate>
</asp:UpdatePanel>
</form>
The buttons are generated dynamically;
foreach (MyDTO myDTO in List) {
Button ButtonPull = new Button();
ButtonPull.Text = "Pull";
ButtonPull.ID = articleDTO.ArticleID.ToString();
ButtonPull.ControlStyle.CssClass = "btn btn-default";
ButtonPull.Click += new EventHandler(Pull_Click);
SiteContent.Controls.Add(ButtonPull);
}
Now the problem is that the event doesn't get called when a user clicks on button. This doesn't work:
protected void Pull_Click(object sender, EventArgs e) {
// Button button = sender as Button;
LabelTest.Text = "Cool";
}
How can I do that?
Thanks.

I am assuming you do not simply want to call the click event but perhaps pass some data from the client to the server via AJAX. The most straightforward way to do this, without ScriptManager, UpdatePantel and all that is like this. I have created one button and it has no click event handler on the server side. But it has one on the client side.
protected void Page_Load(object sender, EventArgs e)
{
Button ButtonPull = new Button();
ButtonPull.Text = "Pull";
ButtonPull.ID = "Button1";
ButtonPull.ControlStyle.CssClass = "btn btn-default";
this.Form.Controls.Add(ButtonPull);
// You can pass anything you want to the server. Here I am passing 1111
// You can pass things from the client side as well. Whole JSON objects as well
ButtonPull.OnClientClick = "callServer(1111);return false;"; // return false so button does not postback
}
I have also added this method to my page's code behind. This is a web method which receives an id as int and appends it to a string and returns that string to the client.
[WebMethod]
[ScriptMethod(UseHttpGet = true,
ResponseFormat = ResponseFormat.Json, XmlSerializeString = false)]
public static string GetStuffFromServer(int id)
{
return "Works like a charm! And id is " + id ;
}
And finally added this to my view. When the button is clicked on the client side, it will call this function and pass 1111 as we instructed it above when we created the button. Inside this function we are using jQuery ajax call to call the server method GetSuffFromServer. If all goes well the server will return and we will go into success here and alert the data returned from the server. Again, the server can return anything needed. And this method can send anything needed to the server.
<script>
function callServer(id) {
$.ajax({
type: "GET",
contentType: "application/json; charset=utf-8",
url: "default.aspx/GetStuffFromServer?id=" + id,
success: function (data)
{
alert(data.d);
},
error: function (data) { alert(data);}
});
}
</script>
One last thing in App_Start folder's RouteConfig.cs file change this line:
settings.AutoRedirectMode = RedirectMode.Permanent;
to this:
settings.AutoRedirectMode = RedirectMode.Off;
This change is because I am using a friendly url when calling the web method: default.aspx/GetStuffFromServer?id=

Related

Asp.net MVC5 application Runtime compilation

Is there any way to make my asp.net mvc5 applications runtime compilation like angular. In traditional way I change in .cshtml file save and press f5 to refresh running page then I get my change effect on page. But is there any way that can reload my page without pressing f5 in browser as like as angular application do.
Ajax refreshes the current page and gets the data from the server.
As shown in the code: ajax calls the Test action method under the PageLoad controller.
The background code is as follows:
public ActionResult Test()
{
var actionResult = default(JsonResult);
var stu = new STU();
this.UpdateModel(stu);
var tmp = string.Format("{0}{1} old from {2}", stu.Name, stu.Age, stu.City);
actionResult = new JsonResult()
{
Data = new { Message = tmp }
};
Thread.Sleep(5000);
return actionResult;
}
According to the student information passed by the front desk, return a string to ajax.
<form id="student_form">
<input type="submit" id="sub" value="submit" />
</form>
$(document).ready(function() {
$('#student_form').submit(function() {
$.ajax({
// ajax submit code....
});
return false;
});
});

Make ASP.NET AJAX function call synchronous

I have an ASP.NET form that calls a web service using ASP.NET AJAX. How do I make the call synchronous?
// test.aspx
<script type="text/javascript">
function GetDescription(){
var code = document.getElementById("<%=txtCode.ClientID%>").value;
var description =
MyNamespace.MyService.GetDescription(
code, onSuccessGetDescription, null, null);
return false;
}
function OnSuccessGetDescription(result){
var txtDescription =
document.getElementById("<%=txtDescription.ClientID%>");
}
</script>
<script type="text/javascript">
$(document).ready(//function () {
$('#<%=cmdSave.ClientID%>').click(function (e) {
e.preventDefault();
if (Page_ClientValidate()){
// Populate jQuery.UI dialog box with code and description
// and then
$("#confirm-dialog").dialog("open");
}
});
}
</script>
<asp:TextBox ID="txtCode" />
<asp:TextBox ID="txtDescription" />
<asp:Button ID="cmdSave" />
// test.aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
txtCode.Attributes["onblur"] = "GetDescription();";
}
The answers to this question that I have seen say that I should set the async attribute to false, but I don't see how to do that here.
ASP.Net Ajax - PageMethods Synchronous call and retrieval of results says that it can't be done. I am trying to get a second opinion.
If I can't make the call synchronous, would it be legal to make GetTransaction poll until the OnSuccess function returns? What would be an efficient (i.e. not CPU-intensive) way to do that?
JQuery Asynchronous
jQuery.ajax({
url: 'http://example.com/catalog/create/' + targetNode.id + '?name=' + encode(to.inp[0].value),
success: function (result) {
if (result.isOk == false) alert(result.message);
},
async: false
});

Logout of Facebook Through Linkbutton

I have been looking through quite a few posts on StackOverflow and on the internet on being able to log a user out of Facebook through an ASP.NET LinkButton.
I have tried implementing solutions from the following posts:
Facebook Logout button in asp.net web application
How to logout from facebook connect in asp.net?
Facebook Logout Confusion
Code
ASPX Page
<asp:LinkButton ID="LogoutButton" CssClass="log-out fb" OnClick="LogoutButton_Click" runat="server">Logout</asp:LinkButton>
JavaScript
$(".log-out.fb").click(function () {
FB.logout(function (response) {
//Logged out
FB.Auth.setAuthResponse(null, 'unknown');
});
});
HTML Output
<a id="MainContent_LogoutButton" class="log-out fb" href="javascript:__doPostBack('ctl00$MainContent$LogoutButton','')" style="width: 66px; ">Logout</a>
I definitely know that the jQuery click event is getting fired when debugging via Firebug. The jQuery code works fine when used in conjunction with a standard HTML anchor, so there is no reason for it not to work on a ASP.NET LinkButton.
Any help would be appreciated.
Thanks for all your help. But I managed to find a way to log out a user by using the following link:
https://www.facebook.com/logout.php?next=YOUR_URL&access_token=ACCESS_TOKEN
I created a callback page similar to the one from this article. Once I received the "access token", I managed to log the user out.
Here is my code for my callback page:
protected void Page_Load(object sender, EventArgs e)
{
if (!String.IsNullOrEmpty(Request["code"]) && !Page.IsPostBack)
{
FacebookCallback();
}
}
private void FacebookCallback()
{
var client = new RestClient { Authority = "https://graph.facebook.com/oauth/" };
var request = new RestRequest { Path = "access_token" };
request.AddParameter("client_id", ConfigurationManager.AppSettings["facebook.appid"]);
request.AddParameter("redirect_uri", ConfigurationManager.AppSettings["facebook.logout.callbackurl"]);
request.AddParameter("client_secret", ConfigurationManager.AppSettings["facebook.appsecret"]);
request.AddParameter("code", Request["code"]);
RestResponse response = client.Request(request);
// A little helper to parse the querystrings.
StringDictionary result = QueryStringHelper.ParseQueryString(response.Content);
string aToken = result["access_token"];
LogUserOut(aToken);
}
private void LogUserOut(string sToken)
{
string url = String.Format("https://www.facebook.com/logout.php?next=http://{0}/Default.aspx&access_token={1}", ConfigurationManager.AppSettings["site.url"], sToken);
Response.Redirect(url);
}
I hope this helps others if they encounter the same issue.

Load ascx via jQuery

Is there a way to load ascx file by jQuery?
UPDATE:
thanks to #Emmett and #Yads. I'm using a handler with the following jQuery ajax code:
jQuery.ajax({
type: "POST", //GET
url: "Foo.ashx",
data: '{}',
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (response)
{
jQuery('#controlload').append(response.d); // or response
},
error: function ()
{
jQuery('#controlload').append('error');
}
});
but I get an error. Is my code wrong?
Another Update :
I am using
error: function (xhr, ajaxOptions, thrownError)
{
jQuery('#controlload').append(thrownError);
}
and this is what i get :
Invalid JSON:
Test =>(this test is label inside my ascx)
and my ascx file after Error!!!
Another Update :
my ascx file is somthing like this:
<asp:DropDownList ID="ddl" runat="server" AutoPostBack="true">
<asp:ListItem>1</asp:ListItem>
<asp:ListItem>2</asp:ListItem>
</asp:DropDownList>
<asp:Label ID="Label1" runat="server">Test</asp:Label>
but when calling ajax i get this error in asp: :(
Control 'ctl00_ddl' of type 'DropDownList' must be placed inside a form tag with runat=server.
thanks to #Yads. but his solution only work with html tag.
Building off Emmett's solution
public class FooHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/html";
context.Response.Write(RenderPartialToString("Foo.ascx"));
}
private string RenderPartialToString(string controlName)
{
Page page = new Page();
Control control = page.LoadControl(controlName);
page.Controls.Add(control);
StringWriter writer = new StringWriter();
HttpContext.Current.Server.Execute(page, writer, false);
return writer.ToString();
}
public bool IsReusable
{
get
{
return false;
}
}
}
Use the following jquery request
jQuery.ajax({
type: "POST", //GET
url: "Foo.ashx",
dataType: "html",
success: function (response)
{
jQuery('#controlload').append(response); // or response
},
error: function ()
{
jQuery('#controlload').append('error');
}
});
public ActionResult Foo()
{
return new ContentResult
{
Content = RenderPartialToString("Foo.ascx", null),
ContentType = "text/html"
};
}
//http://www.klopfenstein.net/lorenz.aspx/render-partial-view-to-string-asp-net-mvc-benchmark
public static string RenderPartialToString(string controlName, ViewDataDictionary viewData)
{
ViewPage vp = new ViewPage();
vp.ViewData = viewData;
Control control = vp.LoadControl(controlName);
vp.Controls.Add(control);
StringBuilder sb = new StringBuilder();
using (StringWriter sw = new StringWriter(sb))
{
using (HtmlTextWriter tw = new HtmlTextWriter(sw))
{
vp.RenderControl(tw);
}
}
return sb.ToString();
}
*.ascx files are rendered on the server side (inside of an *.aspx page), not the client side (where JavaScript is executed).
One option might be to create a blank *.aspx, put the user control on the *.aspx page, and then get that page via jQuery and dump the result on the page.
Edit
Based on your comment, I have another suggestion:
If you're developing a CMS style application, you should build your *.ascx controls so that they are compatible with the ASP.NET AJAX Toolkit. That will allow the users to add content to the page without doing a full refresh.
If you really want to make things nice for the user, you should check out Web Parts and ASP.NET AJAX as Web Parts were really designed so that users could customize the content on their pages.

How can I save an ASP.NET IFRAME from a custom entity's OnSave event, reliably?

I have a custom ASP.NET solution deployed to the ISV directory of an MS Dynamics CRM 4.0 application. We have created a custom entity, whose data entry requires more dynamism than is possible through the form builder within CRM. To accomplish this, we have created an ASP.NET form surfaced through an IFRAME on the entity's main form.
Here is how the saving functionality is currently laid out:
There is an ASP.NET button control on the page that saves the entity when clicked. This button is hidden by CSS.
The button click event is triggered from the CRM OnSave javascript event.
The event fires and the entity is saved.
Here are the issues:
When the app pool is recycled, the first save (or few) may:
not save
be delayed (ie. the interface doesn't show an update, until the page has been refreshed after a few sec)
Save and Close/New may not save
For issue 1.1 and 2, what seems to be happening is that while the save event is fired for the custom ASP.NET page, the browser has moved on/refreshed the page, invalidating the request to the server. This results in the save not actually completing.
Right now, this is mitigated with a kludge javascript delay loop for a few seconds after calling the button save event, inside the entity OnSave event.
Is there any way to have the OnSave event wait for a callback from the IFRAME?
The solution that I've implemented (very recently) to overcome the problem is a little complicated, but let me try to explain:
Essentially - On the page with the iFrame, you're going to track (in Session) the save event and expose the results through a WebMethod that the CRM page will call (using the jquery .ajax() functionality)
Best way to explain is with sample code (Just create a new Website Project with Default.aspx & IFramePage.aspx):
IFramePage.aspx ->
<script type="text/javascript">
SaveStuff = function() {
__doPostBack('SaveButton', '');
}
</script>
Hello - I am an iFrame!<br />
<asp:linkbutton id="SaveButton" runat="server" style="display:none;" onclick="SaveButton_Click" text="Save" />
<asp:hiddenfield id="RandomGuidHiddenField" runat="server" />
</div>
IFramePage.aspx.cs ->
public static object locker = new object();
/// <summary>
/// Gets the statuses.
/// </summary>
/// <value>The statuses.</value>
public static Dictionary<Guid, bool> Statuses
{
get
{
lock (locker)
{
if (HttpContext.Current.Session["RandomGuid"] == null)
{
HttpContext.Current.Session["RandomGuid"] = new Dictionary<Guid, bool>();
}
return (Dictionary<Guid, bool>) HttpContext.Current.Session["RandomGuid"];
}
}
}
[WebMethod]
public static bool CheckSaveComplete(string randomGuid)
{
var currentGuid = new Guid(randomGuid);
var originalTime = DateTime.Now;
if (!Statuses.ContainsKey(currentGuid))
{
Statuses.Add(currentGuid, false);
}
while (!Statuses[currentGuid])
{
if (DateTime.Now.Subtract(originalTime) > new TimeSpan(0, 0, 0, 1))
{
return false;
}
Thread.Sleep(1000);
}
return true;
}
/// <summary>
/// Handles the Load event of the Page control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
this.RandomGuidHiddenField.Value = Guid.NewGuid().ToString();
}
}
/// <summary>
/// Handles the Click event of the SaveButton control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
protected void SaveButton_Click(object sender, EventArgs e)
{
var randomGuid = new Guid(this.RandomGuidHiddenField.Value);
if (!Statuses.ContainsKey(randomGuid))
{
Statuses.Add(randomGuid, false);
}
Thread.Sleep(10000);
Statuses[randomGuid] = true;
}
In my Default.aspx page (to simulate the CRM Form Entity page) ->
<script type="text/javascript">
function OnSave() {
var saveResult = false;
var randomGuid = window.frames[$("#daIframe")[0].id].$("input[id$=RandomGuidHiddenField]").val();
window.frames[$("#daIframe")[0].id].SaveStuff();
$.ajax(
{
async: false,
type: "POST",
url: "IFramePage.aspx/CheckSaveComplete",
contentType: "application/json; charset=utf-8",
dataType: "json",
data: '{"randomGuid" : "' + randomGuid + '"}',
success: function(response) {
if (response.d === true) {
alert(response.d);
saveResult = true;
}
}
}
);
if (saveResult !== true) {
alert("Oh No!");
}
else {
alert("way to go!");
}
}
</script>
<iframe name="daIframe" id="daIframe" src="IFramePage.aspx"></iframe>
<asp:textbox id="lsc_paymentinfo" runat="server" text="1000" /><br />
<input type="button" value="Save" onclick="OnSave();" />
Let me know if you have any questions!
My preferred method of handling the saving of values in an iframe is via webservice. Have the CRM form call a function on your iframe that collects all of the fields and synchronously posts them. When the webservice returns a response and your save function returns, the CRM form will then perform its save.
Here's what your save method on your iframe might look like, using jQuery:
function save() {
var saveResult = false;
$.ajax({
async: false,
type: "POST",
url: "/YourWebservice.asmx/SaveIframeValues",
contentType: 'application/json; charset=utf-8',
dataType: "json"
data: '{ paramname : "paramvalue" }',
success: function(response) {
if (response.d === true) // assuming your webservice returns true upon success
{
saveResult = true;
}
}
});
if (saveResult !== true) {
// alert user, perhaps
// and stop the CRM form from saving
event.returnValue = false;
return false;
} else {
// iframe save was successful, time for a nap
}
}
One thing that would help is to increase the app pool timeout in IIS. Its default is 20 minutes so if nobody uses your IFrame for 20 minutes, it will recycle the app pool and result in a long delay the next time it's fired up.
One solution in that case is to hook on the IFrame State or Events, and continue the CRM save action only when the IFrame is reloaded after the postback. In that way, if the custom app fails or is slow, you can notify the user and cancel the save process.

Resources