ServiceStack - Switch off Snapshot - servicestack

I've followed instructions on how creating a ServiceStack here at:
https://github.com/ServiceStack/ServiceStack/wiki/Create-your-first-webservice
I'm sure I have followed it to the letter, but as soon as I run the web application. I get a 'Snapshot' view of my response. I understand this happens when I don't have a default view/webpage. I set up the project as a ASP.net website, not a ASP.net MVC website. Could that be the problem?
I also wrote a test console application with the following C# code. It got the response as a HTML webpage rather than as a plain string e.g. "Hello, John".
static void sendHello()
{
string contents = "john";
string url = "http://localhost:51450/hello/";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "POST";
request.ContentLength = contents.Length;
request.ContentType = "application/x-www-form-urlencoded";
// SEND TO WEBSERVICE
using (StreamWriter writer = new StreamWriter(request.GetRequestStream()))
{
writer.Write(contents);
}
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
string result = string.Empty;
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
result = reader.ReadToEnd();
}
Console.WriteLine(result);
}
How can I switch off the 'snapshot' view? What am I doing wrong?

The browser is requesting html so ServiceStack is returning the html snapshot.
There are a couple of ways to stop the snapshot view:
First is to use the ServiceClient classes provided by servicestack. These also have the advantage of doing automatic routing and strongly typing the response DTOs.
Next way would be to set the Accept header of the request to something like application/json or application/xml which would serialize the response into json or xml respectively. This is what the ServiceClients do internally
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Accept = "application/json";
...
Another method would be to add a query string parameter called format and set it to json or xml
string url = "http://localhost:51450/hello/?format=json";

Putting the specific format requesting is the practical way to do this
string url = "http://localhost:51450/hello/?format=json";

I suggest simply deleting this feature.
public override void Configure(Container container)
{
//...
this.Plugins.RemoveAll(p => p is ServiceStack.Formats.HtmlFormat);
//...
}
Now all requests with the Content-Type=text/html will be ignored.

Related

Error trying to attach an image to an Azure DevOps wiki page

I have successfully used the Azure DevOps API to create multiple wiki pages, via a standalone C# desktop app. Now I'm trying to attach an image (currently stored locally) to the wiki (as per https://learn.microsoft.com/en-us/rest/api/azure/devops/wiki/attachments/create?view=azure-devops-rest-6.0), but get an error
The wiki attachment creation failed with message : The input is not a
valid Base-64 string as it contains a non-base 64 character, more than
two padding characters, or an illegal character among the padding
characters.
This is the code that I use to read the image file and convert it to a Base64 string - is this correct?
string base64String = null;
string img = File.ReadAllText(att.Value);
byte[] byteCredentials = UTF8Encoding.UTF8.GetBytes(img);
base64String= Convert.ToBase64String(byteCredentials);
Then I create the "content" for the API call as
string data = #"{""content"": """ + base64String + #"""}";
and run the API call
string url = "https://dev.azure.com/{organization}/{project}/_apis/wiki/wikis/{wikiIdentifier}/attachments?name=Image.png&api-version=6.0";
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
request.ContentType = "application/octet-stream";
request.Method = "PUT";
request.Proxy.Credentials = CredentialCache.DefaultCredentials;
request.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(Encoding.ASCII.GetBytes(string.Format("{1}", "AzurePAT"))));
if (data != null)
{
using (StreamWriter writer = new StreamWriter(request.GetRequestStream()))
{
writer.Write(data);
}
}
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
string result = string.Empty;
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
result = reader.ReadToEnd();
}
Can anyone see anything wrong with any of this? The concept of setting up a "content" JSON with an encoded Base64 string doesn't seem to be documented, so have I done it correctly?
Any help or advice gladly appreciated, thanks
An image file does not contain text, it is a binary file, calling File.ReadAllText probably messes up the encoding. Try:
var img = File.ReadAllBytes(att.Value);
var base64String = Convert.ToBase64String(img);
In addition, the request expects the body to just be a string. You are passing JSON. Your code should look like this:
using (StreamWriter writer = new StreamWriter(request.GetRequestStream()))
{
writer.Write(base64String);
}

Problem with Post json data on flask server

i'm setting up a flask server and i would like to do HTTP POST request with a json content-type from android application.
for my purpose i only need to get json data from different client.
one of these client is an android application and it basically do an http post in the server.
the code of android post request is :
public void SendHttp(View view){
new Thread(new Runnable() {
#Override
public void run() {
StringBuffer stringBuffer = new StringBuffer("");
BufferedReader bufferedReader = null;
final String lte_url="http://192.168.1.8:5000/data_center/lte";
HttpPost httpPost = new HttpPost();
try {
HttpClient httpClient = new DefaultHttpClient();
URI uri = new URI("http://192.168.1.8:5000/data_center/lte");
httpPost.addHeader(new BasicHeader(HTTP.CONTENT_TYPE,"application/json"));
httpPost.setURI(uri);
JSONObject send_ = json_lte;
txtSend.setText(""+send_.toString(2));
StringEntity entity = new StringEntity("{"+
"\"date\":"+"\""+send_.getString("Date")+","+
"\"Ping\":"+send_.getString("Ping")+","+
"\"Download\":"+send_.getString("Download")+","+
"\"Upload\":"+send_.getString("Upload")+","+
"\"Latitude\":"+send_.getString("Latitude")+","+
"\"Longitude\":"+send_.getString("Longitude")+","+
"\"Type\":"+send_.getString("Type")+","+
"\"RsRq\":"+send_.getString("RsRq")+","+
"\"RsRp\":"+send_.getString("RsRp")+","+
"\"SINR\":"+send_.getString("SINR")+","+
"\"Bandwidth\":"+send_.getString("Bandwidth")+
"}");
txtSend.setText(entity.toString());
httpPost.setEntity(entity);
HttpResponse httpResponse = httpClient.execute(httpPost);
} catch (some Exeption...)}
}
}).start();
the only output of the flask server is it
Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
192.168.1.237 - - [23/Jul/2019 22:47:58] "POST /data_center/lte HTTP/1.1" 201 -
the code about the server is :
#app.route('/data_center/lte',methods=['POST'])
def post_LTE_data():
try:
data = request.get_json(force=True)
packet = {
'date': data['Date'],
'ping': data['Ping'],
'download': data['Download'],
'upload': data['Upload'],
'latitude': data['Latitude'],
'longitude': data['Longitude'],
'type': data['Type'],
'RsRq': data['RsRq'],
'RsRp': data['RsRp'],
'SINR': data['SINR'],
'bandwidth': data['Bandwidth']
}
lte.append(packet)
return f"OK", 200
except Exception or JsonError as exc:
print(str(exc))
return "some problem"+str(exc), 201
It seems that you have to configure your logging module. You can replace the Python code print(str(exc)) with app.logger.error(str(exc)) to see if it produces some output. You can click here to find some useful code.
By the way, you can take a look at the content received by your Android client because it should receive the response "some problem"+str(exc).
I do not know much about Android code, but it seems that you are dealing with a wrong JSON string. The right format is as below:
{
"foo":"bar",
"good":"bad"
}
In your Android code, you might have to replace
"\"date\":"+"\""+send_.getString("Date")+","
to
"\"date\":"+"\""+send_.getString("Date")+"\","
The above rule should be applied to all lines in the JSON string. Be careful about the symbol "", and you have to make sure that the data during POST is a valid JSON string. Also, I suggest you use another way like utilizing some libraries to build JSON strings to avoid typos.

JAX-WS Authentication SoapUI vs. Client application

I need to create an SOAP client with JAX-WS on JBoss.
The Problem is I cannot get past the authentication.
I have a test implemented in SoapUI which works when I set the request properties username and password
With the following code
URL kbaURL = new URL("http://...");
IkfzService ikfzService = new IkfzService(kbaURL);
IkfzPortType ikfzPortType = ikfzService.getIkfzSOAP();
Map<String, Object> requestContext = ((BindingProvider)ikfzPortType).getRequestContext();
requestContext.put(BindingProvider.USERNAME_PROPERTY, "...");
requestContext.put(BindingProvider.PASSWORD_PROPERTY, "...");
Where URL, username und password are the same like in SOAPUI I am getting
javax.xml.ws.WebServiceException: org.apache.cxf.service.factory.ServiceConstructionException:
Failed to create service.
...
Caused by: javax.wsdl.WSDLException: WSDLException: faultCode=PARSER_ERROR:
Problem parsing 'http://..'.: java.io.IOException: Server returned HTTP response code:
401 for URL: http://..
What am I missing?
This should be a basic example of what you're trying to accomplish - let me know if you need more help or clarification
//the WSDL/webservice endpoint
private static final String WSDL_URL = "http://localhost:8080/MyWebService/MyWebService?wsdl";
URL url = new URL(WSDL_URL);
QName qname = new QName("http://ws.mycompany.com/", MyWebServiceImpl");
Service theWSService = Service.create(url, qname);
//returns the interface for MyWebServiceImpl
TheWSServiceIF port = theWSService.getPort(TheWSServiceIF.class);
//Setup Security
Map<String, Object> requestContext = ((BindingProvider)port).getRequestContext();
requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, WS_URL);
Map<String, List<String>> requestHeaders = new HashMap<String, List<String>>();
requestHeaders.put("Username", Collections.singletonList("myUserName"));
requestHeaders.put("Password", Collections.singletonList("myPasword"));
requestContext.put(MessageContext.HTTP_REQUEST_HEADERS, headers);
/**********************************************************************/
//actually call the web service method, print results
System.out.println(port.getMyWebServiceData());

Can't send volley post request from android phone

I'm using Volley to send an http post request with parameters from my android app to my local server running in http://192.168.1.4:3000/battery_signal_report
I'm pretty sure the server is running properly (I checked it with Postman successfully).
also, I successfully sent the request through Android Studio's Emulator using ip 10.0.2.2
Trying to make it work, i used various request implementations including JsonObjectRequest, StringRequest and the custom request described here: Volley JsonObjectRequest Post request not working
Also, I've read somewhere that Volley post requests have some problems with the request header, so i tried to override it in different ways.
Nothing works. onErrorResponse is called every time with an empty VolleyError input.
I've fairly new to android development, so any insights would be much appreciated.
Thanks in advance.
For anyone else coming across this, you need to forget about the header override and setup your own getBodyContentType() and getBody() methods. Follow this pattern:
StringRequest stringRequest = new StringRequest(Request.Method.POST, url, successListener, errorListener) {
#Override
public String getBodyContentType() {
return "application/json; charset=utf-8";//set here instead
}
#Override
public byte[] getBody() {
try {
Map<String, String> params = yourObject.getMappedParams();
JSONObject json = new JSONObject(params);
String requestBody = json.toString();
return requestBody == null ? null : requestBody.getBytes("utf-8");
} catch (UnsupportedEncodingException uee) {
return null;
}
}
};

Is there a more elegant way to build URIs in ServiceStack?

I'm building a Request/Acknowledge/Poll style REST service with NServiceBus underneath to manage queue processing. I want to give the client a URI to poll for updates.
Therefore I want to return a location header element in my web service as part of the acknowledgement. I can see that it is possible to do this:
return new HttpResult(response, HttpStatusCode.Accepted)
{
Location = base.Request.AbsoluteUri.CombineWith(response.Reference)
}
But for a Url such as: http://localhost:54567/approvals/?message=test, which creates a new message (I know I should probably just use a POST), the location will be returned as: http://localhost:54567/approvals/?message=test/8f0ab1c1a2ca46f8a98b75330fd3ac5c.
The ServiceStack request doesn't expose the Uri fragments, only the AbsouteUri. This means that I need to access the original request. I want this to work regardless of whether this is running in IIS or in a self hosted process. The closest I can come up with is the following, but it seems very clunky:
var reference = Guid.NewGuid().ToString("N");
var response = new ApprovalResponse { Reference = reference };
var httpRequest = ((System.Web.HttpRequest)base.Request.OriginalRequest).Url;
var baseUri = new Uri(String.Concat(httpRequest.Scheme, Uri.SchemeDelimiter, httpRequest.Host, ":", httpRequest.Port));
var uri = new Uri(baseUri, string.Format("/approvals/{0}", reference));
return new HttpResult(response, HttpStatusCode.Accepted)
{
Location = uri.ToString()
};
This now returns: http://localhost:55847/approvals/8f0ab1c1a2ca46f8a98b75330fd3ac5c
Any suggestions? Does this work regardless of how ServiceStack is hosted? I'm a little scared of the System.Web.HttpRequest casting in a self hosted process. Is this code safe?
Reverse Routing
If you're trying to build urls for ServiceStack services you can use the RequestDto.ToGetUrl() and RequestDto.ToAbsoluteUri() to build relative and absolute urls as seen in this earlier question on Reverse Routing. e.g:
[Route("/reqstars/search", "GET")]
[Route("/reqstars/aged/{Age}")]
public class SearchReqstars : IReturn<ReqstarsResponse>
{
public int? Age { get; set; }
}
var relativeUrl = new SearchReqstars { Age = 20 }.ToUrl("GET");
var absoluteUrl = HostContext.Config.WebHostUrl.CombineWith(relativeUrl);
relativeUrl.Print(); //= /reqstars/aged/20
absoluteUrl.Print(); //= http://www.myhost.com/reqstars/aged/20
For creating Urls for other 3rd Party APIs look at the Http Utils wiki for example extension methods that can help, e.g:
var url ="http://api.twitter.com/user_timeline.json?screen_name={0}".Fmt(name);
if (sinceId != null)
url = url.AddQueryParam("since_id", sinceId);
if (maxId != null)
url = url.AddQueryParam("max_id", maxId);
var tweets = url.GetJsonFromUrl()
.FromJson<List<Tweet>>();
You can also use the QueryStringSerializer to serialize a number of different collection types, e.g:
//Typed POCO
var url = "http://example.org/login?" + QueryStringSerializer.SerializeToString(
new Login { Username="mythz", Password="password" });
//Anonymous type
var url = "http://example.org/login?" + QueryStringSerializer.SerializeToString(
new { Username="mythz", Password="password" });
//string Dictionary
var url = "http://example.org/login?" + QueryStringSerializer.SerializeToString(
new Dictionary<string,string> {{"Username","mythz"}, {"Password","password"}});
You can also serialize the built-in NameValueCollection.ToFormUrlEncoded() extension, e.g:
var url = "http://example.org/login?" + new NameValueCollection {
{"Username","mythz"}, {"Password","password"} }.ToFormUrlEncoded();

Resources