Post Data to next Page in Custom Save Action Web Form For Marketer Sitecore 8 - save

After saving data in WFFM Custom save Action,I want to redirect Success Page with some large amount of data
I am trying below line of code .
I Can use Cookies ,session or Query String and Response.Redirect(baseUrl)but i want to Cookies ,session or Query String .
class SaveAction : WffmSaveAction
{
public override void Execute(ID formId, AdaptedResultList adaptedFields, ActionCallContext actionCallContext, params object[] data)
{
//Save Data in Service ,, Redirect to success page with below code with some data like ID
string baseUrl = HttpContext.Current.Request.Url.Scheme + "://" + HttpContext.Current.Request.Url.Authority +
HttpContext.Current.Request.ApplicationPath.TrimEnd('/') + "/success-page";
HttpContext.Current.Response.Clear(); //
StringBuilder sb = new StringBuilder();
sb.Append("<html>");
sb.AppendFormat(#"<body onload='document.forms[""form""].submit()'>");
sb.AppendFormat("<form name='form' action='{0}' method='post'>", baseUrl);
sb.AppendFormat("<input type='hidden' name='id' value='{0}'>", "123456");
// Other params go here
sb.Append("</form>");
sb.Append("</body>");
sb.Append("</html>");
HttpContext.Current.Response.Write(sb.ToString());
HttpContext.Current.Response.End();
// HttpContext.Current.Response.Redirect(baseUrl);
}
}
Above code reload the same page with no body in Html.
Am i missing something in given code ?

The answer might depend on whether you have an mvc form or not.
In case of mvc forms, you might want to read this: http://ggullentops.blogspot.be/2016/07/sitecore-wffm-act-on-success.html. It describes hooking into the success pipeline <wffm.success> and passing data towards the success page (how exactly - querystring, session, .. is up to you(r code)). Fairly easy once you know the correct pipeline.
There is also a great post here describing what you are trying to do - i.e. saving the data for later use in the saveaction. It's too much code to copy here but it comes down to saving the data (in session) during the save action and creating a rendering (to read and handle the data again) that you will place on the success page.
Creating a rendering to place on your success page is something you will have to do anyway.. Don't try to redirect yourself, Sitecore does that for you.

Related

Read API Response Messages

I have Developed ASP.net Core Web API & Web APP Which are in the same solution but different projects.
in the API I have some validations/checking as you may call.
e.g: if user email already exists, the API returns 'Email alreday in use' like this
bool EmailExists = dbContext.Users.Any(u => u.Email == user.Email);
if (EmailExists)
{
return new JsonResult("Email Address already taken!, Try a differen Email");
}
and so on. in some cases I may need to check multiple columns one a time, (eg: UserName, Email, TellNum)
This is an example of calling the API in the MVC
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(_baseAPIUrl);
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage Res = await client.PostAsJsonAsync("Users", user);
if (Res.IsSuccessStatusCode)
{
//in here I want check the `Res` and if it contains the returned messages, I want to display them by assigning it to `TempData[infoMsg]`
// else some something(register user)
}
// Check the returned JsonResult messages here if statusCode is ultered eg: BadRequest
}
My Question is how can I display these types of response messages in razor view in the MVC(Web App). in PostMan its workin, returning the response messages in body.
I did a lot of research about this but couldn't come to conclusion. I also cantacted some Devs I know(not .NET) and they said use JavaScript to call your API, which means I have to change almost everything I have done so far.
I aslo tried ultereing the statuCode to something like BadRequest in the API(if Email exists) in which case it will be checked outside the if (Res.IsSuccessStatusCode) of the Httpclient.
any help or direction is highly appreciated.
You should return a http error and a body containing some data about it eg field and message to your mvc controller. That could be a 422 error or whatever you like really since it's effectively internal and just coming back to the mvc controller.
The controller can then add any such error to modelstate and you can use the razor model "client" validation mechanism to show the error associated with a field.
This is therefore using the same mechanism used for attribute validation in the controller where you'd do
if (!ModelState.IsValid)
This is air code but will hopefully give you the idea.
[HttpPost]
public ActionResult PostUpdate(User u)
{
// call service and await response
var response = await httpClient.PostAsJsonAsync(posturi, u);
var returnContent = await response.Content.ReadAsAsync<ReturnContent>();
if (response.Result != HttpStatusCode.OK)
{
ModelState.AddModelError(returnContent.FieldName,returnContent.Error);
return Page();
}
// etc
You will want a more sophisticated checking on errors of course and check you get the body you're expecting.
Maybe you just hard code the field and error message if there's only one possibility. Maybe work with an array of fields and errors if there could be numerous validation fails.

how to access ViewBag together with Json

I am implementing autocomplete functionality by returning database values with the help of Json and Linq.I need to implement edit functionality. For edit functionality I need to return viewBag data to my view. But I couldn't access my viewBag while returning Json result.
public JsonResult Index(string Prefix,int id = 0)
{
SqlConnection sqcon2 = new SqlConnection(conn);
SqlCommand cmd2 = new SqlCommand();
SqlDataAdapter sd2 = new SqlDataAdapter(cmd2);
DataTable dt2 = new DataTable();
cmd2.Connection = sqcon2;
cmd2.CommandText = "sps_userLocationByID";
cmd2.CommandType = System.Data.CommandType.StoredProcedure;
cmd2.Parameters.AddWithValue("#id", id);
sqcon2.Open();
sd2.Fill(dt2);
sqcon2.Close();
foreach (DataRow dr2 in dt2.Rows)
{
ViewBag.cityName = dr2["CityName"].ToString();
ViewBag.Name = dr2["Name"].ToString();
}
SqlConnection sqcon = new SqlConnection(conn);
SqlCommand cmd = new SqlCommand();
SqlDataAdapter sd = new SqlDataAdapter(cmd);
DataTable dt = new DataTable();
cmd.Connection = sqcon;
cmd.CommandText = "sps_userCity";
cmd.CommandType = System.Data.CommandType.StoredProcedure;
sqcon.Open();
sd.Fill(dt);
sqcon.Close();
List<CityModel> ObjList = new List<CityModel>();
foreach (DataRow dr in dt.Rows)
{
CityModel st = new CityModel();
st.CityName = dr["CityName"].ToString();
ObjList.Add(st);
}
var CityName = (from N in ObjList
where
N.CityName.ToLower().StartsWith(Prefix.ToLower())
select new { N.CityName });
return Json(CityName, JsonRequestBehavior.AllowGet);
}
you can use viewbag if you call another Actionresult method via Ajax.
ViewBag only exists in the context of a Razor view, which itself only exists if you're returning View(), PartialView(), etc. If you're returning JSON, that's all you get. You cannot utilize ViewBag.
That said, I think you're confused in general about how things work though. Initially your app is responding with an HTML document. Everything else, your action, view, etc. is all about getting to this HTML document that can finally be returned to the client, a web browser in this case.
Once that response has been sent. The server is done. Client-side, the web browser parses the document and creates various object models: the DOM, CSSOM, etc. It then uses these object models to render the page (the paint). During and after this process, your JavaScript is run. All of this is happening client-side, and the server doesn't know or care; it's already done its job.
Then, you're wanting some new information from the server. That requires a new request from the client, which will result in a new response from the server. That request could come in the form of navigation by the user within the browser (in which case the whole browser window/tab view will change) or in the form of an AJAX request, which leaves the current view in the browser window/tab as-is.
XMLHttpRequest, the actual JavaScript client class responsible for making AJAX requests, is what's referred to as a "thin client". It makes requests and receives responses, but it does not do anything with said response, in ontrast to a "thick client" like a web browser, which takes the response and does all the object model creation and rendering. Instead, a callback function is merely invoked. It is your responsibility to do something in that callback with the response you receive (update the DOM, etc.)
All this is to say that doing anything with ViewBag while returning a JSON response to an AJAX request makes absolutely zero sense, because the view is not changing. You seem to be imagining that change ViewBag would somehow automatically update something on the page that was previously added via ViewBag in your initial Razor view. That's not the case, and it's not how things work. If you want to alter something on the page, the new value needs to be returning as part of the JSON response from your AJAX request, and then you must use that new value to alter the DOM accordingly.

XSSFWorkbook#write() results in empty response

I'm trying to get my JSF to export a spreadsheet for download. I'm using Apache's POI library for the Excel document writing. I get the following error in an alert box when the code runs:
emptyResponse: An empty response was received from the server.
The method generating the spreadsheet and exporting to the OutputStream is below (I have renamed classes, methods etc for simplicity sake).
private void generateSpreadsheet(Object object) throws Exception {
FacesContext context = FacesContext.getCurrentInstance();
HttpServletResponse response = (HttpServletResponse)context.getExternalContext().getResponse();
String fileName = object.getProperty() + ".xlsx";
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-Disposition", "attachment;filename=\"" + fileName +"\"");
OutputStream os = response.getOutputStream();
Workbook wb = new XSSFWorkbook();
Sheet sheet = wb.createSheet("Sheet 1");
Row row = sheet.createRow(0);
Cell cell = row.createCell(0);
cell.setCellValue("test");
wb.write(os);
os.flush();
os.close();
FacesContext.getCurrentInstance().responseComplete();
}
Any advice much appreciated, thanks.
If it makes a difference, I'm using AJAX (<f:ajax> tag) on the form submit that calls this method.
It makes definitely difference. You can not download files by Ajax. Ajax is executed by JavaScript code. But JavaScript has no facilities to force a Save As dialogue or to execute the platform default application associated with the file's mime type (thankfully; that would have been a major security/intrusion problem). Further, the JSF Ajax API expects a XML response in a specified structure conform the JSF specs. When you send a complete Excel file instead, the whole Ajax response would be ignored as ununderstandable garbage by the JSF Ajax API.
You need to send a normal synchronous request. Remove the <f:ajax> tag from the command link/button. The current page will remain the same anyway if the download is sent as an attachment.

How to check whether username already exists using ajax in asp.net?

I am working on an application which has a registration form and I have to display to the user whether the username exists or not.
I am using asp.net mvc3 and planned to use AJAX to achieve this.
I have a form
<tr>
<td>User Name*</td>
<td><input id="UserName" name="UserName" type="text" onblur="check(this.value);"/></td>
<td id= "UName"></td>
</tr>
which calls a .js file that has the folling contents
function check(User) {
...
var url = "/UserNameCheck/Index";
url += "?User=" + User;
xmlHttp.onreadystatechange = state_Change;
xmlHttp.open("GET", url, true);
xmlHttp.send(null);
}
function state_Change() {
if (xmlhttp.readyState == 4) {// 4 = "Response loaded"
if (xmlhttp.status == 200) {// 200 = Response Error Free
document.getElementById("UName").innerHTML = xmlHttp.responseText
}
else {
alert("Problem retrieving XML data");
}
}
}
I alerted the username and I am getting the correct value that i had entered. Now, the URL is /UserNameCheck/Index where UserNameCheck is a controller and Index is a method in that.
The controller has this code.
public ActionResult Index(string User)
{
string UserName;
try
{
Response.Cache.SetCacheability(HttpCacheability.NoCache);
UserName = Request.QueryString["User"];
ConnectionPackage.ConnectionClass cc = new ConnectionPackage.ConnectionClass();
conn = cc.con;
string sql = "Select UserName FROM UserDetails where UserName = '" + UserName + "'";
conn.Open();
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.CommandType = CommandType.Text;
object p = cmd.ExecuteScalar();
cmd.ExecuteNonQuery();
string u = (string)p;
if (u.Length==0 || u.Equals("NULL") || u.Equals("null")||u.Equals("Null"))
{
return View();
}
return null;
}
catch (Exception ex){
}
and the view has
String buffer = " <table><tr><td id = 'UName' >" This user name already exists. Please select some other unser name.
buffer = buffer + "</td></tr></table>";
response.getWriter().println(buffer);
I also tried writing
Response.Clear();
Response.Write("UserName already exists. Please select another UserName");
Response.End();
instead of returning View.
But in both the cases, I didn't get any message that the username exists even though I typed a user name that was already present in the database.
The connection string work for inserting into the database, so I dont think there is a problem with that. Is there a problem with the URL that I have mentioned in the js file? Or is my entire approach wrong?
I am basically from java background so dont know much about asp.net. Please do help.
Thank you very much in advance.
I followed what was given in MSDN article How to: Implement Remote Validation in ASP.NET MVC
jQuery in Action is the most popular jQuery book
You're doing alright but you could make this a whole lot easier on yourself. If you are usinng MVC3 with Razor, your app already has jQuery installed.
Use the $.ajax() method to perform the calls to your controller action that checks names...
Bind the $.ajax() call "unobtrusively" which means instead of on your HTML control, bind the event to your control from the jquery/javascript.
Second, if you want a little fancy performance, you can bind it via the live() jquery function or keyup event, so that as you are typing the ajax call is made and you find out realtime.
Ultimately you will end up with a lot less javascript, and your JS stuff will be cleanly separated from your markup.
As far as your controller action is going, it looks fine for playing around and learning, but you'd want to think about either (a) putting your SQL statement as a stored procedure on the db server and calling that, or (b) writing a repository pattern class and then using LINQ to do your query work after the DB fetch.
Another possibility would be to use Entity Framework 4.1 via NuGet to eliminate both needs. It can have a bit of a learning curve, but there's lots of good stuff out there and your example would be fairly simple to get started with.
Let me know if you have any specific concerns with your code and I can provide a more detailed answer.

Getting Session in Http Handler ashx

I am using Http Handler ashx file for showing the images.
I was using Session object to get image and return in the response
Now problem is i need to use custom Session object its nothing but the Wrapper on HttpSession State But when i am trying to get existing custom session object its creating new ...
its not showing session data , i checked the session Id which is also different
Please adive how can i get existing session in ashx file ?
Note: When i use ASP.NET Sesssion its working fine
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class GetImage : IHttpHandler, System.Web.SessionState.IRequiresSessionState
{
When you want to get access to your Session State from an ASHX or HttpHandler you need to implement IReadOnlySessionState or IRequiresSessionState if you need read/write access.
The fact that it's an ashx should be irrelevant - assuming the request is being spawned off a request from an exsiting session; I'm assuming it should be - but it might pay to check exactly how the request is being formed. Always pays to go back to basics :)
Assuming that's ok, this is how I've been doing it:
string sessionId = string.Empty;
System.Web.SessionState.SessionIDManager sessionIDManager = new System.Web.SessionState.SessionIDManager();
bool supportSessionIDReissue;
sessionIDManager.InitializeRequest(httpContext, false, out supportSessionIDReissue); sessionId = sessionIDManager.GetSessionID(httpContext);
if (sessionId == null)
{
// Create / issue new session id:
sessionId = sessionIDManager.CreateSessionID(httpContext);
}
At the end of this the sessionId variable will (should) contain the existing Session ID, or a newly created one that you can reuse later..
you can just use a Actionresult rather than a handler for this
return new FileStreamResult(new FileStream(path, FileMode.Open), "image/jpeg");
or
return(new FileResult(Pathtoimage, "image/jpeg"));
that should make things easier as you wil be using a controll/action as your url
ie
<img src="/Images/showImage/1">
you can then have your actions deal with anything like pulling from db as bytes
streaming, check validation etc

Resources