Get return value within an ASIBasicBlock - asihttprequest

I have a view controller which will make a server request. I have put all server request handlers in a single class. So in the view controller, just use [Apihandler getlist] to get list for example.
In class Apihandler, I used block in
[_request setCompletionBlock:^{}]
to get server response (JSON object).
If JSON object contains a key/value named "error", I will take it as failure though it is complete to ASIHttpRequest itself. Otherwise, it is success.
The question is: how do I get the return value of above completion block? I checked ASI document, ASIBasicBlock is void return type.

I did this with a delegate. So I have code that looks like this:
[request setCompletionBlock:^{
NSLog(#"Data retrieved");
NSData *data = [request responseData];
NSLog(#"Status Code: %d", [request responseStatusCode]);
dispatch_async(backgroundQueue, ^(void){
[self processData:data];
});
}];
Which basically says when this completion block runs, call the processData message in the background. In the processData message I make use a delegate to return data to my main UI thread. That message looks like this:
- (void)processData:(NSData *)data {
NSError *error = nil;
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
dispatch_async(dispatch_get_main_queue(), ^(void){
[self.delegate requestDataReady:json];
});
}
I hope that helps.
UPDATE:
Of course you don't have to run the process method in a background thread. You could just as easily call [self processData:data] within the block or even place the code from processData inside of the block.

Related

OCMock does not return stubbed value in a new instance

I have the below class written
#implementation B
- (NSString *)returnMock{
return #"BBB";
}
#end
And I have the below test written:
- (void)testB {
id mockB = [OCMockObject mockForClass:[B class]];
[[[mockB stub] andReturn:#"mock"] returnMock];
//This check is a pass
XCTAssertEqualObjects(#"mock", [mockB returnMock]);
B *b = [[B alloc] init];
//This check is a fail
XCTAssertEqualObjects(#"mock", [b returnMock]);
}
As I understand that, if a mock is created for a class and then for any new instance of it will refer to the mocked class.
If this is not true, can anyone help me in making the second assert to pass after a new instance is created.
Thanks
A mock object can be used instead of an instance of the class. Creating a mock object does not affect instances of the class. If you want to mock methods in an existing instance you must use a partial mock for that specific instance.

Variable inside $http not reflecting change outside block

I am writing a web app in Angular, this piece of code is meant to get test XML data as text from the server. I am using Angular's $http service to send a GET request from the server. The variable 'xmlData' is being changed inside the $http block, but outside that block its value is still the default value. Here's the code:
this.getData = function() {
var xmlData = "Default";
var xmlDoc;
// send an http GET request for the XML text data
$http.get('http://localhost:1337/testXML.txt').success(function(data) {
xmlData = data;
if (xmlData == null) {
alert("Data Error Occurred");
}
// here, 'xmlData' contains the correct information.
}).
error(function() {
alert("HTTP Error Occurred");
});
// once the above $http block ends, the xmlData has the default value.
return xmlData;
}
So is this just a silly scope issue? Or am I using Angular's $http service incorrectly?
Thanks!
I don't think you can directly insert XML like you can JSON without some sort of parser.
Check out this question for handling XML in AngularJS: How to handle XML services in AngularJS?
Specifically check out these modules/plugins to help:
https://github.com/johngeorgewright/angular-xml
https://code.google.com/p/jquery-xml2json-plugin/

Chain the completion of an async function to another

I am working on a Windows Store (C++) app. This is a method that reads from the database using the web service.
task<std::wstring> Ternet::GetFromDB(cancellation_token cancellationToken)
{
uriString = ref new String(L"http://myHost:1234/RestServiceImpl.svc/attempt");
auto uri = ref new Windows::Foundation::Uri(Helpers::Trim(uriString));
cancellationTokenSource = cancellation_token_source();
return httpRequest.GetAsync(uri, cancellationTokenSource.get_token()).then([this](task<std::wstring> response)->std::wstring
{
try
{
Windows::UI::Popups::MessageDialog wMsg(ref new String(response.get().c_str()), "success");
wMsg.ShowAsync();
return response.get();
}
catch (const task_canceled&)
{
Windows::UI::Popups::MessageDialog wMsg("Couldn't load content. Check internet connectivity.", "Error");
wMsg.ShowAsync();
std::wstring abc;
return abc;
}
catch (Exception^ ex)
{
Windows::UI::Popups::MessageDialog wMsg("Couldn't load content. Check internet connectivity.", "Error");
wMsg.ShowAsync();
std::wstring abc;
return abc;
}
} , task_continuation_context::use_current());
}
I'm confused how to return the received data to the calling function. Now, I am calling this function in the constructor of my data class like this:
ternet.GetFromDB(cancellationTokenSource.get_token()).then([this](task<std::wstring> response)
{
data = ref new String(response.get().c_str());
});
I am getting a COM exception whenever I try to receive the returned data from GetFromDB(). But this one runs fine:
ternet.GetFromDB(cancellationTokenSource.get_token());
Please suggest a better way of chaining the completion of GetFromDB to other code. And how to get the returned value from inside the try{} block of GetFromDB() 's then. Please keep in mind I am a very new student of async programming.
If the continuation of the call to GetFromDB is happening on the UI thread (which I believe it will by default, assuming the call site you pasted is occurring in the UI thread), then calling get() on the returned task will throw an exception. It won't let you block the UI thread waiting for a task to finish.
Two suggestions, either of which should fix that problem. The first should work regardless, while the second is only a good option if you're not trying to get the response string to the UI thread (to be displayed, for example).
1) Write your continuations (lambdas that you pass to then) so that they take the actual result of the previous task, rather than the previous task itself. In other words, instead of writing this:
ternet.GetFromDB(...).then([this](task<std::wstring> response) { ... });
write this:
ternet.GetFromDB(...).then([this](std::wstring response) { ... });
The difference with the latter is that the continuation machinery will call get() for you (on a background thread) and then give the result to your continuation function, which is a lot easier all around. You only need to have your continuation take the actual task as an argument if you want to catch exceptions that might have been thrown by the task as it executed.
2) Tell it to run your continuation on a background/arbitrary thread:
ternet.GetFromDB(...).then([this](task<std::wstring> response) { ... }, task_continuation_context::use_arbitrary());
It won't care if you block a background thread, it only cares if you call get() on the UI thread.

Razor view - emitting html outside Doctype tag

I am trying to write a module/areas based mvc3 CMS using razor view engine. I have two layout views, _site.cshtml and _modules.cshtml. The _site.cshtml has an #RenderBody() section. My application always calls a view called "index.cshtml" which has its layout set to _site.cshtml page.
The Problem: The problem is that my modules/areas are rendered before doctype element - and not inside the RenderBody section of layout page.
It looks like what you're trying to do is the equivalent of Html.RenderAction (or Html.Action), so why are you writing all that code yourself instead of using the built-in functionality?
In short, its your Invoke() method! The razor engine works by writing to an in memory stream, and then parses it to the response. The reason you are getting that behaviour is because your Invoke() method is writing straight to the response stream; i.e. before the in memory stream is parsed.
I came across similar behaviour when using the Html.RenderAction(), which pointed to an action that returned a PartialView. The workaround was to use Html.Action(). The difference being is that Action() returns a string which gets appended to the in memory stream, and RenderAction() writes to the directly to the response.
If you post the code for your Invoke() method, I may be able to help you futher!
| -- Edit -- |
OK, this turned out to be more complex that initially anticipated. The problem is that I could not get ProcessRequest() to append to the current response; however, I may have a solution.
public string ProcessRoute(ViewContext viewContext, RouteData routeData)
{
var urlHelper = new UrlHelper(viewContext.RequestContext);
var currentUrl = urlHelper.Action(routeData.Values["action"].ToString(),
routeData.Values["controller"].ToString(), routeData.DataTokens);
var stringWriter = new StringWriter();
var simpleWorkerRequest = new SimpleWorkerRequest(currentUrl, "", stringWriter);
var context = new HttpContext(simpleWorkerRequest);
var contextBase = new HttpContextWrapper(context);
var requestContext = new RequestContext(contextBase, routeData);
var httpHandler = routeData.RouteHandler.GetHttpHandler(requestContext);
httpHandler.ProcessRequest(context);
context.Response.End();
stringWriter.Flush();
return stringWriter.GetStringBuilder().ToString();
}
The code above generates a new Request and returns the Request's HTML as a string. By doing this, the result is appended as part of the current response. You can now rewrite your Invoke() function to return a string, which can be displayed on your View.
public string Invoke(ViewContext viewContext)
{
if (_mvcHandler == null)
{
var routeData = new RouteData(context.RouteData.Route,
context.RouteData.RouteHandler);
routeData.Values.Add("id", _id);
routeData.Values.Add("moduleName", _moduleName);
routeData.Values.Add("controller", _controllerName);
routeData.Values.Add("action", _actionName);
routeData.Values.Add("pageContext", _pageContext);
if (!string.IsNullOrEmpty(_preferredNamespace))
{
routeData.DataTokens.Add("Namespaces", new[] { _preferredNamespace });
}
return ProcessRoute(viewContext, routeData);
}
return string.Empty;
}
You may also have to change;
mr.Invoke(ViewContext);
To;
Html.Raw(mr.Invoke(ViewContext));
In order stop the HTML encoding behaviour.
| -- Note -- |
Since I don't have your ModuleRequests class, I couldn't test this code specifically for your scenario. Instead, I replicated the problem as best as I could and solved it.
Please let me know if you have any questions.
Matt
Let me post a plausible second alternative to your methods while I try and solve the problem above.
There is a html extension in MVC called Html.Partial(), which allows you to use routedata to return the result of a controller action.
So, if you had an AccountController with an Register method that returned a PartialView result, then it would be appended to the current page.
public class AccountController() : Controller
{
public ActionResult Register()
{
return PartialView();
}
}
The call to this action could look something like;
#Html.Partial("Account", "Register");
| -- Note -- |
Don't use #Html.RenderPartial(), or you will have the same problem as above!
I am currently posting away from a computer, so I can't test this theory!
Hope this helps!
Matt

java.lang.IllegalStateException: Cannot (forward | sendRedirect | create session) after response has been committed

This method throws
java.lang.IllegalStateException: Cannot forward after response has been committed
and I am unable to spot the problem. Any help?
int noOfRows = Integer.parseInt(request.getParameter("noOfRows"));
String chkboxVal = "";
// String FormatId=null;
Vector vRow = new Vector();
Vector vRow1 = new Vector();
String GroupId = "";
String GroupDesc = "";
for (int i = 0; i < noOfRows; i++) {
if ((request.getParameter("chk_select" + i)) == null) {
chkboxVal = "notticked";
} else {
chkboxVal = request.getParameter("chk_select" + i);
if (chkboxVal.equals("ticked")) {
fwdurl = "true";
Statement st1 = con.createStatement();
GroupId = request.getParameter("GroupId" + i);
GroupDesc = request.getParameter("GroupDesc" + i);
ResultSet rs1 = st1
.executeQuery("select FileId,Description from cs2k_Files "
+ " where FileId like 'M%' and co_code = "
+ ccode);
ResultSetMetaData rsm = rs1.getMetaData();
int cCount = rsm.getColumnCount();
while (rs1.next()) {
Vector vCol1 = new Vector();
for (int j = 1; j <= cCount; j++) {
vCol1.addElement(rs1.getObject(j));
}
vRow.addElement(vCol1);
}
rs1 = st1
.executeQuery("select FileId,NotAllowed from cs2kGroupSub "
+ " where FileId like 'M%' and GroupId = '"
+ GroupId + "'" + " and co_code = " + ccode);
rsm = rs1.getMetaData();
cCount = rsm.getColumnCount();
while (rs1.next()) {
Vector vCol2 = new Vector();
for (int j = 1; j <= cCount; j++) {
vCol2.addElement(rs1.getObject(j));
}
vRow1.addElement(vCol2);
}
// throw new Exception("test");
break;
}
}
}
if (fwdurl.equals("true")) {
// throw new Exception("test");
// response.sendRedirect("cs2k_GroupCopiedUpdt.jsp") ;
request.setAttribute("GroupId", GroupId);
request.setAttribute("GroupDesc", GroupDesc);
request.setAttribute("vRow", vRow);
request.setAttribute("vRow1", vRow1);
getServletConfig().getServletContext().getRequestDispatcher(
"/GroupCopiedUpdt.jsp").forward(request, response);
}
forward/sendRedirect/sendError do NOT exit the method!
A common misunderstanding among starters is that they think that the call of a forward(), sendRedirect(), or sendError() would magically exit and "jump" out of the method block, hereby ignoring the remnant of the code. For example:
protected void doXxx() {
if (someCondition) {
sendRedirect();
}
forward(); // This is STILL invoked when someCondition is true!
}
This is thus actually not true. They do certainly not behave differently than any other Java methods (expect of System#exit() of course). When the someCondition in above example is true and you're thus calling forward() after sendRedirect() or sendError() on the same request/response, then the chance is big that you will get the exception:
java.lang.IllegalStateException: Cannot forward after response has been committed
If the if statement calls a forward() and you're afterwards calling sendRedirect() or sendError(), then below exception will be thrown:
java.lang.IllegalStateException: Cannot call sendRedirect() after the response has been committed
To fix this, you need either to add a return; statement afterwards
protected void doXxx() {
if (someCondition) {
sendRedirect();
return;
}
forward();
}
... or to introduce an else block.
protected void doXxx() {
if (someCondition) {
sendRedirect();
}
else {
forward();
}
}
To naildown the root cause in your code, just search for any line which calls a forward(), sendRedirect() or sendError() without exiting the method block or skipping the remnant of the code. This can be inside the same servlet before the particular code line, but also in any servlet or filter which was been called before the particular servlet.
In case of sendError(), if your sole purpose is to set the response status, use setStatus() instead.
Do not write any string before forward/sendRedirect/sendError
Another probable cause is that the servlet writes to the response while a forward() will be called, or has been called in the very same method.
protected void doXxx() {
out.write("<p>some html</p>");
// ...
forward(); // Fail!
}
The response buffer size defaults in most server to 2KB, so if you write more than 2KB to it, then it will be committed and forward() will fail the same way:
java.lang.IllegalStateException: Cannot forward after response has been committed
Solution is obvious, just don't write to the response in the servlet. That's the responsibility of the JSP. You just set a request attribute like so request.setAttribute("data", "some string") and then print it in JSP like so ${data}. See also our Servlets wiki page to learn how to use Servlets the right way.
Do not write any file before forward/sendRedirect/sendError
Another probable cause is that the servlet writes a file download to the response after which e.g. a forward() is called.
protected void doXxx() {
out.write(bytes);
// ...
forward(); // Fail!
}
This is technically not possible. You need to remove the forward() call. The enduser will stay on the currently opened page. If you actually intend to change the page after a file download, then you need to move the file download logic to page load of the target page. Basically: first create a temporary file on disk using the way mentioned in this answer How to save generated file temporarily in servlet based web application, then send a redirect with the file name/identifier as request param, and in the target page conditionally print based on the presence of that request param a <script>window.location='...';</script> which immediately downloads the temporary file via one of the ways mentioned in this answer Simplest way to serve static data from outside the application server in a Java web application.
Do not call forward/sendRedirect/sendError in JSP
Yet another probable cause is that the forward(), sendRedirect() or sendError() methods are invoked via Java code embedded in a JSP file in form of old fashioned way <% scriptlets %>, a practice which was officially discouraged since 2003. For example:
<!DOCTYPE html>
<html lang="en">
<head>
...
</head>
<body>
...
<% sendRedirect(); %>
...
</body>
</html>
The problem here is that JSP internally immediately writes template text (i.e. HTML code) via out.write("<!DOCTYPE html> ... etc ...") as soon as it's encountered. This is thus essentially the same problem as explained in previous section.
Solution is obvious, just don't write Java code in a JSP file. That's the responsibility of a normal Java class such as a Servlet or a Filter. See also our Servlets wiki page to learn how to use Servlets the right way.
See also:
What exactly does "Response already committed" mean? How to handle exceptions then?
Unrelated to your concrete problem, your JDBC code is leaking resources. Fix that as well. For hints, see also How often should Connection, Statement and ResultSet be closed in JDBC?
even adding a return statement brings up this exception, for which only solution is this code:
if(!response.isCommitted())
// Place another redirection
Typically you see this error after you have already done a redirect and then try to output some more data to the output stream. In the cases where I have seen this in the past, it is often one of the filters that is trying to redirect the page, and then still forwards through to the servlet. I cannot see anything immediately wrong with the servlet, so you might want to try having a look at any filters that you have in place as well.
Edit: Some more help in diagnosing the problem…
The first step to diagnosing this problem is to ascertain exactly where the exception is being thrown. We are assuming that it is being thrown by the line
getServletConfig().getServletContext()
.getRequestDispatcher("/GroupCopiedUpdt.jsp")
.forward(request, response);
But you might find that it is being thrown later in the code, where you are trying to output to the output stream after you have tried to do the forward. If it is coming from the above line, then it means that somewhere before this line you have either:
output data to the output stream, or
done another redirect beforehand.
Good luck!
You should add return statement while you are forwarding or redirecting the flow.
Example:
if forwardind,
request.getRequestDispatcher("/abs.jsp").forward(request, response);
return;
if redirecting,
response.sendRedirect(roundTripURI);
return;
This is because your servlet is trying to access a request object which is no more exist..
A servlet's forward or include statement does not stop execution of method block. It continues to the end of method block or first return statement just like any other java method.
The best way to resolve this problem just set the page (where you suppose to forward the request) dynamically according your logic. That is:
protected void doPost(request , response){
String returnPage="default.jsp";
if(condition1){
returnPage="page1.jsp";
}
if(condition2){
returnPage="page2.jsp";
}
request.getRequestDispatcher(returnPage).forward(request,response); //at last line
}
and do the forward only once at last line...
you can also fix this problem using return statement after each forward() or put each forward() in if...else block
I removed
super.service(req, res);
Then it worked fine for me
Bump...
I just had the same error. I noticed that I was invoking super.doPost(request, response); when overriding the doPost() method as well as explicitly invoking the superclass constructor
public ScheduleServlet() {
super();
// TODO Auto-generated constructor stub
}
As soon as I commented out the super.doPost(request, response); from within doPost() statement it worked perfectly...
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//super.doPost(request, response);
// More code here...
}
Needless to say, I need to re-read on super() best practices :p
After return forward method you can simply do this:
return null;
It will break the current scope.
If you see this on a Spring based web application, make sure you have your method annotated with #ResponseBody or the controller annotated with #RestController instead of #Controller. It will also throw this exception if a method returns JSON, but has not been configured to have that as the response, Spring will instead look for a jsp page to render and throw this exception.

Resources