URL Encoding in c# and Asp.net web api - c#

I have an ASP.NET web api that receives web requests and returns Json data.
browsing to this URL:
http://1.2.3.4/api1/api/values/mypartname will return the following json string:
{
\"PartName\": \"mypartname\",
\"PartDes\": \"53.6X53.6APA/ALIM1NOTPAK\",
\"PartLocation\": \"A36\"
}
but when sending a part name that contains spaces or quotes like this: http://1.2.3.4/api1/api/values/my part na"me i get a 404 - File or directory not found. error.
I'm consuming the json with a .NET 4 Console application like so:
static void Main(string[] args)
{
try
{
string partName = "TAPE 56 3M 3/4\"";
WebRequest wr = WebRequest.Create("http://1.2.3.4/api1/api/values/" +
HttpUtility.UrlEncode(partName));
wr.Credentials = CredentialCache.DefaultCredentials;
HttpWebResponse hwr = (HttpWebResponse)wr.GetResponse();
Stream dataStream = hwr.GetResponseStream();
StreamReader reader = new StreamReader(dataStream);
string json = reader.ReadToEnd();
//some json parsing function
des(json);
reader.Close();
dataStream.Close();
hwr.Close();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
Console.ReadKey();
}
}
the exception is thrown at this line:HttpWebResponse hwr = (HttpWebResponse)wr.GetResponse();
and the exception message is: The remote server returned an error: (404) Not Found.
Am i doing something wrong with the mypartname? I also tried to manually replace the problematic characters according to this: HTML URL Encoding Reference and using this function:Uri.EscapeDataString(partName) but with no luck.
EDIT
this is the routeConfig definition:
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
and the api GET method:
// GET api/values/5
public string Get(string id)
{
List<dummy> dummies = new List<dummy>();
string con = "user id=sa;" +
"password=1234" +
"server=someServer\\someInstance;" +
"database=game; " +
"connection timeout=30";
//SqlConnection sqlConn = new SqlConnection(con);
using (SqlConnection sqlconn = new SqlConnection(con))
{
sqlconn.Open();
StringBuilder sb = new StringBuilder();
sb.Append("SELECT PART.PARTNAME,PART.PARTDES, PARTPARAMA.LOCATION ");
sb.Append("FROM PART LEFT JOIN PARTPARAMA ");
sb.Append("ON PART.PART = PARTPARAMA.PARTPARAM ");
sb.Append("WHERE PART.PARTNAME = #part");
using (SqlCommand cmd = new SqlCommand(sb.ToString(), sqlconn))
{
cmd.Parameters.AddWithValue("part", id);
SqlDataReader sdr = cmd.ExecuteReader();
while (sdr.Read())
{
dummies.Add(new dummy
{
PartName = sdr.IsDBNull(0) ? "Unknown" : sdr.GetString(0),
PartDes = sdr.IsDBNull(1) ? "Unknown" : sdr.GetString(1),
PartLocation = sdr.IsDBNull(2) ? "Unknown" : sdr.GetString(2)
});
}
}
}
if (dummies.Count() > 0)
{
string json = JsonConvert.SerializeObject(dummies[0]);
return json;
}
else
{
string json = JsonConvert.SerializeObject(null);
return json;
}

EDIT 10 Apr 2015:
I am leaving this answer here for anyone who finds it in a search, however as Kevin states below and Scott Hanselman says here:
[UrlPathEncode] doesn't do what you think it does ... This method was
very specific, poorly named, and is now totally obsolete.
I think your problem has more to do with the forward slash in the part name.
You can handle the spaces and quotes using
HttpUtility.UrlPathEncode(partName)
instead of HttpUtility.UrlEncode(partName).
Handling the forward slash is more problematic. See this post for more details.

Related

Transfer image capture photo from Phone gap to C# asp.net Web Service

Below is my j query function uploadPicOne()
$(function() {
var allVals = []; //for global check boxes
$(document).on("click", ".click-action-for-event", function(e) {
debugger;
//current i am calling this method for upload picture
uploadPicOne();
})
});
var uploadPicOne = function() {
navigator.camera.getPicture(updateProfilePicService_one, onFail, {
quality: 50,
destinationType: navigator.camera.DestinationType.FILE_URI,
encodingType: navigator.camera.EncodingType.JPEG,
sourceType: navigator.camera.PictureSourceType.CAMERA
});
}
var updateProfilePicService_one = function(fileUri) {
SpinnerPlugin.activityStart("Loading...", { dimBackground: true });
var options = new FileUploadOptions();
options.fileKey = "image";
options.fileName = fileUri.substr(fileUri.lastIndexOf('/') + 1);
options.mimeType = "image/jpeg";
options.params = {
"status": "B2",
"iTrainingId": $("#iTrainingId_currentprogramme").val(),
"session_date": $("#iTrainingDate_currentprogramme").val(),
};
options.headers = {
"X-Api-Key": localStorage.getItem("auth_key"),
};
options.chunkedMode = false;
var ft = new FileTransfer();
console.log(options);
ft.upload(fileUri, base_url + "uploadpic", win, fail, options);
}
Below is my webservice not sure its work for phone gap
[WebMethod]
public string uploadpic()
{
string msg = "";
using (SqlConnection con = new SqlConnection(strConn))
{
SqlCommand cmd = new SqlCommand("App_Service", con);
cmd.CommandType = CommandType.StoredProcedure;
try
{
var request = HttpContext.Current.Request;
IEnumerable<string> headers = request.Headers.GetValues("X-Api-Key");
var auth_key = headers.FirstOrDefault();
// HttpPostedFile file = HttpContext.Current.Request.Files["image"];
HttpPostedFile file = HttpContext.Current.Request.Files[0];
string saveFile = file.FileName;
file.SaveAs(Server.MapPath("/Trainer_Images/" + saveFile));
cmd.Parameters.AddWithValue("#Paravalue", "14");
cmd.Parameters.AddWithValue("#Value", saveFile);
cmd.Parameters.AddWithValue("#Value1", auth_key);
cmd.Parameters.AddWithValue("#Value2", "0");
cmd.Parameters.AddWithValue("#Value3", "0");
con.Open();
cmd.ExecuteNonQuery();
cmd.Dispose();
con.Close();
con.Dispose();
//Context.Response.Write(JSONResult);
//return d1.data;
/// msg = "File uploaded";
}
catch (Exception ex)
{
msg = "Could not upload file: " + ex.Message;
}
}
return msg;
}
I need to know my web service is correct or wrong. I am not able to run my webservice also, my requirement is send captured image file to my asp.net web-service and save to database, please help me to achieve my requirement or any suggestion or any examples related my need. The above jquery functions are working fine because the same app using into different application.
Today I have checked this code is not working through mobile showing loading after taking photo from mobile.
I think you are making asp.net web service (asmx).It needs ajax enabled to be called from JavaScript.
For your project i think you should use Asp.net mvc API
check this article.
https://www.c-sharpcorner.com/article/uploading-image-to-server-using-web-api-2-0/

Returning success message from JSON post

I have the following to post JSON to a C# Web API:
submitForm(data: any): Observable<Response> {
return this.http.post(
'https://localhost:44396/api/PostNewComputer/AddItem/?=', data,
{ headers: new Headers({ 'Content-Type': 'application/x-www-form-urlencoded' }) }).subscribe(data => { return "test"; });
}
And the API controller:
public class PostNewComputerController : ApiController
{
[HttpPost]
public IHttpActionResult AddItem(HttpRequestMessage request)
{
//var dynamicObject = Json.Decode(jsonString);
var jsonString = request.GetQueryNameValuePairs();
string message;
using (SqlConnection con = new SqlConnection("data source = MYSERVER; initial catalog = AssetDB; integrated security = SSPI; persist security info = True; Trusted_Connection = Yes"))
{
using (SqlCommand cmd = new SqlCommand("POST_NEW_COMPUTER", con) { CommandType = CommandType.StoredProcedure })
{
try
{
cmd.Parameters.Add(new SqlParameter("#JSON_TEXT", SqlDbType.NVarChar)).Value = jsonString;
con.Open();
cmd.ExecuteNonQuery();
con.Close();
message = "Item Successfully Added";
}
catch (Exception e)
{
//throw e;
message = e.Message;
}
}
return Ok(message);
}
}
}
I am trying to create a response message from the POST call that is then fed back to the webpage when the user submits the form to show that the post has worked.
However, this current setup doesn't work and I am struggling to solves this.
Is there a correct way to do this properly?
Use HttpResponseMessage to post back message as:
[HttpPost]
[ResponseType(typeof(string))]
public HttpResponseMessage AddItem(HttpRequestMessage request)
{
HttpResponseMessage response = null;
string message = string.Empty;
try
{
.....
message = "Item Successfully Added";
}
catch (Exception e)
{
.....
message = e.Message;
}
response = Request.CreateResponse<string>(HttpStatusCode.OK, message);
return response;
}
The problem is in your Angular service. Your API is correct
You're trying to subscribe to the response from your API before mapping it back to json(), you need to do the following, see below:
Firstly this is what should be in your component:
submitForm(data: any): Observable<Response> {
//this url can't be correct?
let url:string = 'https://localhost:44396/api/PostNewComputer/AddItem/?=';
return this.http.post(url, data, this._headers())
.map((res:Response) => res.json());
}
//Created a method to do the headers for you
private _headers():RequestOptionsArgs {
let headers:Headers = new headers();
headers.append('Content-Type', 'application/json');
let options:RequestOptionsArgs = new RequestOptions();
options.headers = headers;
return options;
}
You would then call your service from your component as follows:
public functionName():void {
this.service.submitForm(data)
.subscribe((res:any) => {
//this will contain your response
},
(error:any) => {
//this will contain your error
});
}
You need to ensure the model you're posting matches the model expected. With regards to the URL you are posting to, that seems incorrect, is it not https://localhost:44396/api/PostNewComputer/AddItem/?

No HTTP resource was found that matches the request URI 'MyUrl'

I created a .Net web service:
public class UsersController : ApiController
{
[System.Web.Http.HttpPost]
public void Post(string value)
{
SqlConnection connection = new SqlConnection("Data Source=198.71.226.6;Integrated Security=False;User ID=AtallahMaroniteDB;Password=a!m?P#$$123;Database=AtallahPlesk_;Connect Timeout=15;Encrypt=False;Packet Size=4096");
String query = "INSERT INTO Members(LastName, FirstName, Gender, MobileNumber, EmailAddress, Job, Address) VALUES " +
"(#LastName, #FirstName, #Gender, #MobileNumber, #EmailAddress, #Job, #Address)";
SqlCommand command = new SqlCommand(query, connection);
try
{
JavaScriptSerializer json_serializer = new JavaScriptSerializer();
PersonModel person = json_serializer.Deserialize<PersonModel>(value);
command.Parameters.Add("#LastName", person.LastName);
command.Parameters.Add("#FirstName", person.FirstName);
command.Parameters.Add("#Gender", person.Gender);
command.Parameters.Add("#MobileNumber", person.MobileNumber);
command.Parameters.Add("#EmailAddress", person.EmailAddress);
command.Parameters.Add("#Job", person.Job);
command.Parameters.Add("#Address", person.Address);
connection.Open();
command.ExecuteNonQuery();
}
catch (Exception ex)
{
Console.WriteLine(ex.InnerException.ToString());
}
}
}
And the following is my routing config:
RouteTable.Routes.MapHttpRoute(
name: "MyApi",
routeTemplate: "api/{controller}/{action}/{value}"
);
When I am calling this web service from an Android or iOS application, I am getting the following error:
No HTTP resource was found that matches the request URI
'http://www.mytestdomain.com/api/users/post'
Below is the android code:
JSONObject dato = POST(person); // This method converts the Person object to JSONObject
String text = null;
try {
HttpPost post = new HttpPost("http://www.mytestdomain.com/api/users/post");
StringEntity entity = new StringEntity(dato.toString());
entity.setContentType(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));
post.setEntity(entity);
HttpResponse response = httpClient.execute(post);
HttpEntity entityResponse = response.getEntity();
text = getASCIIContentFromEntity(entityResponse);
} catch ( IOException ioe ) {
ioe.printStackTrace();
}
Please note that when I call this web service from postman, it's posting the data successfully.
Please let me know if you need any further details.
You need to update your route template to make sure that you get a valid match for your request.
Here is what a valid template would look like for your API. Note this is specific to the UsersController as the defaults: has been set to controller = "Users" which will map to the UsersController
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Attribute routing.
config.MapHttpAttributeRoutes();
// Convention-based routing.
config.Routes.MapHttpRoute(
name: "MyApi",
routeTemplate: "api/users/{action}",
defaults: new { controller = "Users" }
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
From your code example you are sending the model as json and then trying to manually parse it on the server. You can let the framework parse the model with its model binders based on the Content-Type of the request. This will allow you to update your action to accept the actual object model instead of a string.
public class UsersController : ApiController {
//eg: POST api/users/post
[HttpPost]
public IHttpActionResult Post(PersonModel person) {
if (person == null) return BadRequest();
try
{
SqlConnection connection = new SqlConnection("Data Source=198.71.226.6;Integrated Security=False;User ID=AtallahMaroniteDB;Password=a!m?P#$$123;Database=AtallahPlesk_;Connect Timeout=15;Encrypt=False;Packet Size=4096");
String query = "INSERT INTO Members(LastName, FirstName, Gender, MobileNumber, EmailAddress, Job, Address) VALUES " +
"(#LastName, #FirstName, #Gender, #MobileNumber, #EmailAddress, #Job, #Address)";
SqlCommand command = new SqlCommand(query, connection);
command.Parameters.Add("#LastName", person.LastName);
command.Parameters.Add("#FirstName", person.FirstName);
command.Parameters.Add("#Gender", person.Gender);
command.Parameters.Add("#MobileNumber", person.MobileNumber);
command.Parameters.Add("#EmailAddress", person.EmailAddress);
command.Parameters.Add("#Job", person.Job);
command.Parameters.Add("#Address", person.Address);
connection.Open();
command.ExecuteNonQuery();
}
catch (Exception ex)
{
Console.WriteLine(ex.InnerException.ToString());
return InternalServerError();
}
return Ok();
}
}
You also need to make sure the request sent is correct so you can get a match
Here is a raw example request snippet
POST /api/users/post HTTP/1.1
Host: http://www.mytestdomain.com
Content-Type: application/json
...
Content-Length: 163
{"LastName":"Doe","FirstName":"Jane","Gender":"Female","MobileNumber":"+1234567890","EmailAddress":"jane.doe#example.com","Job":"Developer","Address":"My address"}
Try inspecting the requests sent from the mobile to make sure its being sent correctly. Something like Fiddler.

Android use WCF(webservice)

I am a freshman in android development. Today I use KSOAP2 to use WCF which I have finished on the server. Firstly, I try to use the WCF in windows form. It runs OK and the data have been upload. Then I use WCF with KSOAP2. The string cannot send well and the error is :
Method threw 'org.ksoap2.SoapFault' exception.
The detial of the error is:
a:InternalServiceFault
Value cannot be null.
Parameter name: s
I do not have the parameter named 's' in server program and android program. The vision of .NET is framework 4.0.
If I use .NET framework 4.5, The android can use it with KSOAP2.
However, I must use 4.0
How can I solve this problems?
Cheers.
The code in android is shown below:
transferthread = new Thread(new Runnable() {
#Override
public void run() {
while (true)
{
SoapObject request = new SoapObject(NAMESPACE,METHOD_NAME);
int a = 1;
request.addProperty("userid",a);
request.addProperty("healthData",info);
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER10);
envelope.dotNet = true;
envelope.bodyOut = request;
envelope.setOutputSoapObject(request);
HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
androidHttpTransport.debug = true;
try {
androidHttpTransport.call(SOAP_ACTION, envelope);
// final SoapPrimitive result = (SoapPrimitive)envelope.getResponse();
envelope.getResponse();
Log.e("str",envelope.getResponse().toString());
a=1;
//Log.e("aaa",envelope.getResponse().toString());
} catch (IOException e) {
e.printStackTrace();
} catch (XmlPullParserException e) {
e.printStackTrace();
}
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
transferthread.start();
I think is the ksoap2 problem.
My answer is another alternative solution for your question about how to implement Android use WCF. I used to give a try on KSOAP2. For some reason (I forgot) I give up using it.
This is what I am doing to do the same thing.
You can install Wizdler(Chrome-extension) to generate your envelope. and copy paste to envelope code.
Call getYourData in your asynctask.
public ArrayList<YourData> getYourData(String username, String password) {
ArrayList<YourData> resultList;
String resultData;
try {
//Put your envelope here.
final String envelope = "<Envelope xmlns=\"http://schemas.xmlsoap.org/soap/envelope/\">\n" +
" <Body>\n" +
" <Something xmlns=\"http://www.example.com/RemoteServices/url/\">\n" +
" <!-- Optional -->\n" +
" <request>\n" +
" <Authentication xmlns=\"http://schemas.datacontract.org/RemoteServicesv2.Core\">\n" +
" <Password>" +
password +
"</Password>\n" +
" <Username>" +
username +
"</Username>\n"
" </Something>\n" +
" </Body>\n" +
"</Envelope>";
resultData = CallWebService(URL, "http://www.example.com/webserviceURL", envelope);
Log.e("resultData for Something", ""+resultData);
resultList = parseFunction(resultData);
} catch (Exception e) {
resultList = null;
}
return resultList;
}
// How to send SOAP envelope to web service
private String CallWebService(String url,
String soapAction,
String envelope) {
final DefaultHttpClient httpClient = new DefaultHttpClient();
// request parameters
HttpParams params = httpClient.getParams();
HttpConnectionParams.setConnectionTimeout(params, 20000);
HttpConnectionParams.setSoTimeout(params, 25000);
// set parameter
HttpProtocolParams.setUseExpectContinue(httpClient.getParams(), true);
// POST the envelope
HttpPost httppost = new HttpPost(url);
// add headers
httppost.setHeader("soapaction", soapAction);
httppost.setHeader("Content-Type", "text/xml; charset=utf-8");
String responseString = "";
try {
// the entity holds the request
HttpEntity entity = new StringEntity(envelope);
httppost.setEntity(entity);
// Response handler
ResponseHandler<String> rh = new ResponseHandler<String>() {
// invoked when client receives response
public String handleResponse(HttpResponse response)
throws ClientProtocolException, IOException {
// get response entity
HttpEntity entity = response.getEntity();
// read the response as byte array
StringBuffer out = new StringBuffer();
byte[] b = EntityUtils.toByteArray(entity);
// write the response byte array to a string buffer
out.append(new String(b, 0, b.length));
return out.toString();
}
};
responseString = httpClient.execute(httppost, rh);
} catch (Exception e) {
Log.v("exception", e.toString());
}
String xml = responseString.toString();
// close the connection
System.out.println("xml file ------" + xml);
httpClient.getConnectionManager().shutdown();
return responseString;
}

Wrong JSON output from Web Api inside asp.net webforms

Am trying to use Web Api to output some json within an ASP.Net web forms web application.
Below is my get method:
public string Get()
{
String paramOne = "paramOneValue";
using (var conn = new SqlConnection(sqlConStr))
{
try
{
var command = new SqlCommand("getMyList", conn);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddWithValue("#paramOne", paramOne);
conn.Open();
ArrayList result = new ArrayList();
var reader = command.ExecuteReader();
while (reader.Read())
{
result.Add(new
{
id = reader[0],
val= reader[1],
val1= reader[2]
});
}
return JsonConvert.SerializeObject(result);
}
catch (SqlException sxp)
{
string msg = Resource.fetchError + " " + sxp.Message;
return "error";
}
}
}
and below is the Response from firebug when the method is called within an aspx page:
"[{\"id\":1,\"val\":\"valFromDB\",\"val1\":\"valOneFromDB\"},{\"id\":2,\"val\":\"row2ValFromDB\",\"val1\":\"row2ValOneFromDB\"}]"
but the weird thing is under JSON tab individual characters are being returned as in below:
0 "["
1 "{"
2 """
3 "i"
4 "d"
Anything am missing?

Categories