I am learning android and webservices. I have an android application that sends data using okHttp and I need to ingest that data on my server and put it into the database. I have a little experience calling and getting data from webservices but have never received data.
As I understand it, in ASP.Net I will need to use a HttpHandler and I have seen some examples but they always seem to be returning data per the request. How do you keep the HttpHandler always listening for this particular incoming data?
Here is the code from my sample android application.
public class MainActivity extends Activity {
TextView outputText;
Button sendData;
EditText edtUser, edtPass;
final String URL = "http://serviceapi.skholingua.com/open-feeds/display_received_params.php";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
outputText = (TextView) findViewById(R.id.textView1);
outputText.setMovementMethod(new ScrollingMovementMethod());
sendData = (Button) findViewById(R.id.button1);
edtUser = (EditText) findViewById(R.id.editText1);
edtPass = (EditText) findViewById(R.id.editText2);
sendData.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
String userName = edtUser.getText().toString();
String passWord = edtPass.getText().toString();
OkHttpHandler handler = new OkHttpHandler(userName, passWord);
String result = null;
try {
result = handler.execute(URL).get();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
outputText.append(result + "\n");
}
});
}
The Class
public class OkHttpHandler extends AsyncTask<String, Void, String> {
OkHttpClient client = new OkHttpClient();
String userName, passWord;
public OkHttpHandler(String userName, String passWord) {
// TODO Auto-generated constructor stub
this.userName = userName;
this.passWord = passWord;
}
#Override
protected String doInBackground(String... params) {
RequestBody formBody = new FormEncodingBuilder()
.add("name", userName)
.add("pass", passWord)
.build();
Request request = new Request.Builder()
.url(params[0]).post(formBody)
.build();
try {
Response response = client.newCall(request).execute();
if (!response.isSuccessful())
throw new IOException("Unexpected code " + response.toString());
return response.body().string();
} catch (Exception e) {
}
return null;
}
The URL will be changed to whatever I create on my server. My question is.. What type of data will this be sending? What do I need to create on my server to ingest it?
If anyone has an example that would be very helpful.
Look into Web API.
Example to read a POST to address hxxp://yourdomain/test/[variable]/[variable] and GET to address hxxp://yourdomain/test/[id]. For example:
hxxp://yourdomain/test2/1 will return the string "You requested number 1"
hxxp://yourdomain/test2/2 will return the string "You requested number 2"
Controller:
public class TestController : ApiController {
[Route("test/{username}/{password}")]
[AcceptVerbs("POST")]
public string Post(string username, string password) {
if(username == "user" && password == "pass") { // check user/pass
string data = Request.Content.ReadAsStringAsync().Result;
//do something
return "User is authenticated";
}
}
[Route("test2/{id}")] {
[AcceptVerbs("GET")]
public string GetData(int id) {
return "You requested number " + id;
}
}
In your example above you would call:
hxxp://yourdomain/test/name/pass
And get the response "User is authenticated"
Related
I have created a chat using SignalR2. The client and server itself works fine. Now, I'm trying to implement a 'users online' function. The server code seems about right, but I'm struggling to make the client receive the data that the server pushes back to the client.
This is the server code below:
public static List<string> Users = new List<string>();
public void Send(string name, string message)
{
// Call the broadcastMessage method to update clients.
Clients.All.broadcastMessage(name, message);
Clients.All.addMessage(name, message);
}
public void SendUserList(List<string> users)
{
var context = GlobalHost.ConnectionManager.GetHubContext<chatHub>();
context.Clients.All.updateUserList(users);
}
public override Task OnConnected()
{
string clientId = GetClientId();
//if (Users.IndexOf(clientId) == -1)
//{
Users.Add(clientId);
//}
SendCount(Users.Count);
return base.OnConnected();
}
public override Task OnDisconnected(bool stopCalled)
{
System.Diagnostics.Debug.WriteLine("Disconnected");
SendCount(Users.Count);
return base.OnDisconnected(stopCalled);
}
private string GetClientId()
{
string clientId = "";
if (Context.QueryString["clientId"] != null)
{
// clientId passed from application
clientId = this.Context.QueryString["clientId"];
}
if (string.IsNullOrEmpty(clientId.Trim()))
{
clientId = Context.ConnectionId;
}
return clientId;
}
public void SendCount(int count)
{
// Call the addNewMessageToPage method to update clients.
var context = GlobalHost.ConnectionManager.GetHubContext<chatHub>();
context.Clients.All.updateUsersOnlineCount(count);
}
Below is the client code for connecting / receiving messages:
public static async void ConnectAsync(RadChat ChatInternal)
{
ChatInternal.Author = new Author(null, Varribles.Agent);
var querystringData = new Dictionary<string, string>();
querystringData.Add("clientId", Varribles.Agent);
Connection = new HubConnection(ServerURI, querystringData);
HubProxy = Connection.CreateHubProxy("chatHub");
//Handle incoming event from server: use Invoke to write to console from SignalR's thread
HubProxy.On<string, string>("AddMessage", (name, message) =>
ChatInternal.Invoke((Action)(() =>
Backend.GET.Messages(ChatInternal)
)));
try
{
await Connection.Start();
Backend.GET.Messages(ChatInternal);
}
catch (System.Net.Http.HttpRequestException)
{
//No connection: Don't enable Send button or show chat UI
return;
}
}
Now, my question is, how can I retrieve the 'Users' list from the server?
Thanks in advance
As my question states, I have a c# web API (MVC.NET web API 2) with a controller having a POST method that receives the post request (Json String) and simply writes it to a log file (for simplicity just making sure I have received it from android app). On the other hand I have an Android app that uses Volley to send a post string request to a mentioned API. I have used a couple of approaches such as using Stringrequest, JsonObject request etc but none of which seemed to work (I get 400 error code). I have tested the API in postman and everything is okay...I'm receiving the posted string in the API post method. Please help me guys or my job is hanging in the balance if I fail to get this task accomplished. Thanks in advance. My code is attached herewith below:
Web API controller
public class TestController : ApiController
{
// POST: api/test
[HttpPost]
[Route("api/test")]
public void Post()
{
string param = Request.Content.ReadAsStringAsync().Result;
EventLogger.writeErrorLog("Posted payload --> " + param)
}
}
Android code to send post
private void postDummy() {
String url = "http://10.0.2.2:1106/api/test";
RequestQueue requestQueue = Volley.newRequestQueue(this);
JSONObject jsonBodyObj = new JSONObject();
try{
jsonBodyObj.put("payload", "XYZ");
}catch (JSONException e){
e.printStackTrace();
}
final String requestBody = jsonBodyObj.toString();
Log.d("Json :--> ", requestBody);
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.POST,
url, null, new Response.Listener<JSONObject>(){
#Override public void onResponse(JSONObject response) {
Log.i("Response",String.valueOf(response));
}
}, new Response.ErrorListener() {
#Override public void onErrorResponse(VolleyError error) {
VolleyLog.e("Error: ", error.getMessage());
}
}){
#Override
public String getBodyContentType() {
return "application/json";
}
#Override
public byte[] getBody() {
try {
return requestBody == null ? null : requestBody.getBytes("utf-8");
} catch (UnsupportedEncodingException uee) {
VolleyLog.wtf("Unsupported Encoding while trying to get the bytes of %s using %s",
requestBody, "utf-8");
return null;
}
}
};
requestQueue.add(jsonObjectRequest);
}
Error Log from Android Studio
D/Json :-->: {"payload":"XYZ"}
E/Volley: [561] BasicNetwork.performRequest: Unexpected response code 400 for http://10.0.2.2:1106/api/test
E/Volley: 1 6.onErrorResponse: Error:
Postman test result
A screenshot for Web API test result
My case was very similar, C# web API return 400 when i call from android volley (whit custom headers). The solution (in my case) was simple, just i removed "Content-Type" "application/json" and let volley do whatever it do.
My code working:
ANDROID:
try{
JSONObject postparams = new JSONObject();
postparams.put("param1", "1");
postparams.put("param2", "2");
String URL=sesion.urlAire + "api/adjunto/getArchivo";
RequestQueue requestQueue= Volley.newRequestQueue(context);
JsonObjectRequest objectRequest=new JsonObjectRequest(
Request.Method.POST,
URL,
postparams,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
//do something
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
//do something
}
}
)
{
#Override
public Map getHeaders() throws AuthFailureError {
HashMap headers = new HashMap();
//headers.put("Content-Type", "application/json");
headers.put("authorization", sesion.token);
return headers;
}
};
requestQueue.add(objectRequest);
}catch (Exception e){}
C#:
[HttpPost]
public CustomObject getArchivo(PostData postData) {
return new CustomObject{ param1="1" };
}
I'm new to Xamarin and I'm trying to create a cross-platform app where users can login using a JSON API call. A token is then returned on a successful login attempt which I can use in other API's to display user data.
It works when I use the same code in a console application, but when I run it in Xamarin the code after await client.GetAsync(url) is never reached and after a while the application breaks and I get an unknown error. Am I experiencing a deadlock?
private async void loginButton_Click(object sender, EventArgs e)
{
var login = await loginAPI(LoginPage.nameEntry.Text, LoginPage.passEntry.Text);
if (login.state == "success")
{
...
}
else
{
...
}
}
public static async Task<LoginData> loginAPI(String username, String password)
{
try
{
using (var client = new HttpClient())
{
var loginUrl = new Uri("https://my-api/login?username=" + username + "&password=" + password);
var result = await client.GetAsync(loginUrl);
return JsonConvert.DeserializeObject<LoginData>(await result.Content.ReadAsStringAsync());
}
}
catch (Exception e)
{
return null;
}
}
public class LoginData
{
[JsonProperty("state")]
public String state { get; set; }
[JsonProperty("token")]
public String token { get; set; }
}
I'm creating a bot using Bot Framework in C#
I have this piece of code :
var faq = await result;
if (faq == "Faq with menu")
{
await context.PostAsync("Under construction");
}
else if (faq == "Faq with dialog")
{
context.Call(new FaqDialog(), this.ResumeAfterOptionDialog);
}
Faq with dialog I have connected with a dialog class.
I want to connect Faq with menu with my client in Api.ai. Do you have any idea how to do it?
What I would do is to create an enum with the Faq values:
Public enum Faq{
Undefined,
Menu,
Dialog
}
Then create a method that will call Api.ai with the user message and map the intent response to the enum:
public T MatchAiIntent<T>(string message) where T : struct, IConvertible
{
if (!typeof(T).IsEnum)
{
throw new ArgumentException("T must be an enum type!");
}
T result = default(T);
try
{
var response = apiAi.TextRequest(message);
var intentName = response?.Result?.Metadata?.IntentName;
if (intentName == null)
{
return result;
}
Enum.TryParse<T>(intentName, true, out result);
return result;
}
catch (Exception exception)
{
//logit
throw;
}
}
Then you can use it in your code:
var response = MatchAiIntent(faq);
if (response == Faq.Menu)
{
await context.PostAsync("Under construction");
}
[UPDATE]
CONNECTING TO Dialogflow (previously known as API.AI) FROM C#
Follow these steps (working example in C#)
After you create a Dialogflow agent go to the agent's settings --> General --> click on the Service Account link
You will be sent to to google cloud platform where you can create a service account
After you create a service account, there will be an option to create a KEY, create it and download the (JSON) format of it
This key will be used to connect from your C# project to the Dialogflow agent
Install Google.Cloud.Dialogflow.V2 package in your project
Create for example a Dialogflow manager class (check below for an example)
public class DialogflowManager {
private string _userID;
private string _webRootPath;
private string _contentRootPath;
private string _projectId;
private SessionsClient _sessionsClient;
private SessionName _sessionName;
public DialogflowManager(string userID, string webRootPath, string contentRootPath, string projectId) {
_userID = userID;
_webRootPath = webRootPath;
_contentRootPath = contentRootPath;
_projectId = projectId;
SetEnvironmentVariable();
}
private void SetEnvironmentVariable() {
try {
Environment.SetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS", _contentRootPath + "\\Keys\\{THE_DOWNLOADED_JSON_FILE_HERE}.json");
} catch (ArgumentNullException) {
throw;
} catch (ArgumentException) {
throw;
} catch (SecurityException) {
throw;
}
}
private async Task CreateSession() {
// Create client
_sessionsClient = await SessionsClient.CreateAsync();
// Initialize request argument(s)
_sessionName = new SessionName(_projectId, _userID);
}
public async Task < QueryResult > CheckIntent(string userInput, string LanguageCode = "en") {
await CreateSession();
QueryInput queryInput = new QueryInput();
var queryText = new TextInput();
queryText.Text = userInput;
queryText.LanguageCode = LanguageCode;
queryInput.Text = queryText;
// Make the request
DetectIntentResponse response = await _sessionsClient.DetectIntentAsync(_sessionName, queryInput);
return response.QueryResult;
}
}
And then this can be called like this for example to get detect Intents
DialogflowManager dialogflow = new DialogflowManager("{INSERT_USER_ID}",
_hostingEnvironment.WebRootPath,
_hostingEnvironment.ContentRootPath,
"{INSERT_AGENT_ID");
var dialogflowQueryResult = await dialogflow.CheckIntent("{INSERT_USER_INPUT}");
There is a need to receive user data using a token. Hello. There is a need to receive user data using a token. I have a web api + websockets, websockets connection via a web browser.
var webSocket = new WebSocket(handlerUrl);
//Open connection handler.
webSocket.onopen = function () {
webSocket.send("{\"type\":\"LOGIN\",\"access_token\":\"Bearer HIDDEN\"}");
};
Once connected, I immediately send token.
On the server side, it looks as follows:
public class SocketClientController: ApiController
{
public HttpResponseMessage Get ()
{
HttpContext.Current.AcceptWebSocketRequest (new WebSocketHandler ());
return Request.CreateResponse (HttpStatusCode.SwitchingProtocols);
}
<miss>
Socket class:
<miss>
private void Login(string access_token)
{
// here i want get user info
}
public override void OnMessage(string input)
{
dynamic data = JObject.Parse(input);
switch ((string)data.type)
{
case "LOGIN":
Login((string)data.access_token);
break;
}
}
I use Identity, a variant with a token when you first received from the client suits me the data. Tell me how you can get the user input without going through the login and password, and use [Authorize].
Sorry for my english.
I decided my task! Below is the code:
public class MachineKeyProtector : Microsoft.Owin.Security.DataProtection.IDataProtector
{
private readonly string[] _purpose =
{
typeof(OAuthAuthorizationServerMiddleware).Namespace,
"Access_Token",
"v1"
};
public byte[] Protect(byte[] userData)
{
throw new NotImplementedException();
}
public byte[] Unprotect(byte[] protectedData)
{
return System.Web.Security.MachineKey.Unprotect(protectedData, _purpose);
}
}
Use:
var secureDataFormat = new TicketDataFormat(new Providers.MachineKeyProtector());
AuthenticationTicket ticket = secureDataFormat.Unprotect(access_token);
var userId = ticket.Identity.GetUserId();