I have an ASP.NET Web API which is supposed to call a java addition web service. When i run the java web service and type url http://localhost:8080/addition/9/6 i get {"firstNumber":9,"secondNumber":6,"sum":15}as the output data. Right now, i want to use the ASP.NET Web API to call and display that data when i run the ASP.NET Web API application. How do i go about doing that?
Here are my codes:
ASP.NET Web API Codes
RestfulClient.cs
public class RestfulClient
{
private string BASE_URL = "http://localhost:8080/addition/";
public Task<string> addition()
{
{
try
{
var client = new HttpClient();
client.BaseAddress = new Uri(BASE_URL);
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = client.GetAsync("addition").Result;
return response.Content.ReadAsStringAsync();
}
catch (Exception e)
{
HttpContext.Current.Server.Transfer("ErrorPage.html");
}
return null;
}
}
}
ApiController.cs
private RestfulClient restfulClient = new RestfulClient();
public ActionResult Index()
{
var Result1 = restfulClient.addition().Result;
return Content(Result1);
}
Java Web Service Codes
AdditionController.java
#RestController
public class AdditionController {
private static final String template = " %s";
private static int getSum;
#RequestMapping("/addition/{param1}/{param2}")
#ResponseBody
public Addition getSum
(#PathVariable("param1") int firstNumber,#PathVariable("param2") int secondNumber) {
return new Addition(
(String.format(template, firstNumber)), String.format(template, secondNumber));
}
}
Someone please help me. Thank you so much in advance.
According to the Java service, the URL you are calling from the client is not formatted correctly based on your base URL and the one used in the GetAsync.
public class RestfulClient {
private static HttpClient client;
private static string BASE_URL = "http://localhost:8080/";
static RestfulClient() {
client = new HttpClient();
client.BaseAddress = new Uri(BASE_URL);
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
}
public async Task<string> addition(int a, int b) {
try {
var endpoint = string.Format("addition/{0}/{1}", a, b);
var response = await client.GetAsync(endpoint);
return await response.Content.ReadAsStringAsync();
} catch (Exception e) {
HttpContext.Current.Server.Transfer("ErrorPage.html");
}
return null;
}
}
The controller would also need to be updated.
public async Task<ActionResult> Index() {
int a = 9;
int b = 6;
var result = await restfulClient.addition(a, b);
return Content(result);
}
Note the proper use of the HttpClient as suggested in the comments and as well as the use of async/await.
Related
Hello I'm new to Java and Springboot. I'm currently working with an API where before making a POST request, I would need to generate a Bearer token. In order to generate a Bearer token, I would need to pass in my basic auth credentials to the "/oauth/token" endpoint. My application is having trouble passing my basic auth credentials since by the time I hit the "/v1/some-endpoint", I'm denied authorization because the Bearer token is null.
Here's my initial solution thinking I could check the url in the interceptor, then executing the following line but after debugging, it doesn't seem to be hitting that line.
Is there something I'm missing or not implementing correctly? Am I not implementing the Basic Auth endpoint correctly? Let me know if you need more information. Thanks
#Profile("!offline")
#FeignClient(
value = "someClient",
url = "${someProperty.url}",
configuration = SomeClient.SomeClientConfig.class)
public interface someClient {
#PostMapping("/v1/some-endpoint")
void redeemSomething(someRequestBody data);
#PostMapping("/oauth/token")
static BasicAuthResponse getBasicAuthToken() {
return new BasicAuthResponse();
}
#AllArgsConstructor
class SomeClientConfig extends BaseClientConfig {
private final SomeProperties properties;
private final SomeAuthTokenSupplier tokenSupplier = new SomeAuthTokenSupplier();
#Bean
#Override
public CloseableHttpClient apacheClient() {
return apacheClientFactory(properties.getUseProxy());
}
#Bean
public RequestInterceptor someAuthInterceptor() {
return template -> {
if(template.url().equals("/oauth/token")) {
String authToken = Base64Utils.encodeToString((properties.getCredentials().getUser() + ":" + properties.getCredentials().getUser()).getBytes(Charset.forName("UTF-8")));
template.header("Authorization", authToken);
}
template.header("Authorization", String.format("Bearer %s", tokenSupplier.getToken()));
};
}
private class SomeAuthTokenSupplier {
private volatile String token;
private volatile long retrievedOn = -1L;
String getToken() {
if (updateTokenRequired()) {
synchronized (this) {
if (updateTokenRequired()) {
BasicAuthResponse tokenResponse = getBasicAuthToken();
token = tokenResponse.getAccess_token(); // new token from some api should be assigned here
retrievedOn = Instant.now().toEpochMilli();
}
}
}
return token;
}
private boolean updateTokenRequired() {
return token == null || LocalDateTime.now().minusHours(8L).isAfter(LocalDateTime.ofInstant(Instant.ofEpochMilli(retrievedOn), ZoneId.systemDefault()));
}
}
#Override
public Retryer retryer() {
return new ClientRetry(250L, 2, 3) {
#Override
public void continueOrPropagate(RetryableException e) {
if (e.status() == 401 || e.status() == 403) {
tokenSupplier.token = null;
}
super.continueOrPropagate(e);
}
};
}
}
}
It worth using standard Spring Security OAuth2 Client feature instead in order to support authorization in Feign clients
See docs and code samples: https://docs.spring.io/spring-security/site/docs/current/reference/html5/#oauth2client
UPD
See another code sample: https://github.com/int128/feign-oauth2-example
If several service endpoints require different authentication, then it's worth having several Feign clients, each with own configuration
In my app I am using netflix zuul to route a request from a microservice (gateway) to another. The requests are being routed fine but I also want to introduce some parameters in the request body before it is routed to the appropriate microservice. For this I am using Zuul pre filter like this.
public class SimpleFilter extends ZuulFilter {
private static Logger log = LoggerFactory.getLogger(SimpleFilter.class);
#Override
public String filterType() {
return "pre";
}
#Override
public int filterOrder() {
return 1;
}
#Override
public boolean shouldFilter() {
return true;
}
#Override
public Object run() {
try {
RequestContext context = RequestContext.getCurrentContext();
InputStream in = (InputStream) context.get("requestEntity");
if (in == null) {
in = context.getRequest().getInputStream();
}
String body = StreamUtils.copyToString(in, Charset.forName("UTF-8"));
// body = "request body modified via set('requestEntity'): "+ body;
body = body.toUpperCase();
context.set("requestEntity", new ByteArrayInputStream(body.getBytes("UTF-8")));
} catch (IOException e) {
log.error(e.getMessage(), e);
}
return null;
}
}
For now I am just trying to change the body to upper case but the microservice to which this request is routed doesn't receive the modified body (upper case). Instead it receives the original one. Am I doing something wrong. Any help would be appreciated. Thanks !!
Was able to do the following - transform a GET request to a POST request, and add body content to the (proxied) POST request.
public Object run() throws ZuulException {
RequestContext context = RequestContext.getCurrentContext();
context.addZuulRequestHeader("Content-Type", "application/x-www-form-urlencoded");
String body = String.format("a=%s&b=%s", a, b);
final byte[] bytes = body.getBytes(StandardCharsets.UTF_8);
context.setRequest(new HttpServletRequestWrapper(context.getRequest()) {
#Override
public ServletInputStream getInputStream() {
return new ServletInputStreamWrapper(bytes);
}
#Override
public int getContentLength() {
return bytes.length;
}
#Override
public long getContentLengthLong() {
return bytes.length;
}
#Override
public String getMethod() {
return "POST";
}
});
return null;
}
try this one It's may be work in your case .
requestContext.getCurrentContext().put("requestEntity", new ByteArrayInputStream(body.getBytes("UTF-8")));
Turned out this method cannot change the request body within the requestContext. Truly in the requestContext, a new field "requestEntity" is added, however, the request body from context.getRequest().getInputStream() remains the same after this operation.
You can modify the request body, see this answer for an example. You just need to wrap the new request data and make sure you correctly report it's new content length.
Been trying to follow some online examples as I need to do basic authentication on a webservice client.
I generated the stub classes of the project using wsimport and tried passing the authentication credentials using javax.xml.rpc.stub class but casting the proxy class throws a java.lang.ClassCastException:
com.sun.proxy.$Proxy29 cannot be cast to javax.xml.rpc.Stub.
please can anyone review this code and point me in the right direction if am doing something wrong.
public class WebClientTester
{
public static void main(String[] args)
{
doNameEnquiry("XXXXXXXXX");
}
public static void doNameEnquiry(String acct)
{
boolean txnOk = false;
try
{
String str = "http://XXX.XXX.XXX.XXX/GwHolderService.svc?wsdl";
URL url = new URL(str.substring(0, str.indexOf("?")));
QName qname = new QName("http://tempuri.org/", "GwHolderService");
Service service = Service.create(url, qname);
SInfoHolder port = (SInfoHolder) service.getPort(SInfoHolder.class);
((javax.xml.rpc.Stub) port)._setProperty(javax.xml.rpc.Stub.USERNAME_PROPERTY, "myUser");
((javax.xml.rpc.Stub) port)._setProperty(javax.xml.rpc.Stub.PASSWORD_PROPERTY, "myPwd");
InfoHolderRequest request = new InfoHolderRequest();
request.setHolderAccountNumber(acct);
InfoHolderResponse response = port.infoHolder(request);
// System.out.println("authenticated: "+
// response.getRespMessageCode());
System.out.println("******************END RESPONSE***********");
System.out.println("responseCode: " + response.getCoderesp());
System.out.println(processResponseXML(response));
System.out.println("******************LIST DETAILS***********");
listDetails(processResponseXML(response));
}
catch (Exception ex)
{
ex.printStackTrace();
}
// return txnOk;
}
}
I'm trying to obtain a list of a user's tweets and I've run into some trouble when trying to authenticate my call to the API. I currently get a 401 when executing the code below:
public interface TwitterApi {
String API_URL = "https://api.twitter.com/1.1";
String CONSUMER_KEY = "<CONSUMER KEY GOES HERE>";
String CONSUMER_SECRET = "<CONSUMER SECRET GOES HERE>";
String ACCESS_TOKEN = "<ACCESS TOKEN GOES HERE>";
String ACCESS_TOKEN_SECRET = "<ACCESS TOKEN SECRET GOES HERE>";
#GET("/statuses/user_timeline.json")
List<Tweet> fetchUserTimeline(
#Query("count") final int count,
#Query("screen_name") final String screenName);
}
The following throws a 401 Authorisation error when calling fetchUserTimeline()
RetrofitHttpOAuthConsumer consumer = new RetrofitHttpOAuthConsumer(TwitterApi.CONSUMER_KEY, TwitterApi.CONSUMER_SECRET);
consumer.setTokenWithSecret(TwitterApi.ACCESS_TOKEN, TwitterApi.ACCESS_TOKEN_SECRET);
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(TwitterApi.API_URL)
.setClient(new SigningOkClient(consumer))
.build();
TwitterApi twitterApi = restAdapter.create(TwitterApi.class)
tweets = twitterApi.fetchUserTimeline(2, screenName);
I've also included the relevant code from the signpost-retrofit plugin:
public class SigningOkClient extends OkClient {
private final RetrofitHttpOAuthConsumer mOAuthConsumer;
public SigningOkClient(RetrofitHttpOAuthConsumer consumer) {
mOAuthConsumer = consumer;
}
public SigningOkClient(OkHttpClient client, RetrofitHttpOAuthConsumer consumer) {
super(client);
mOAuthConsumer = consumer;
}
#Override
public Response execute(Request request) throws IOException {
Request requestToSend = request;
try {
HttpRequestAdapter signedAdapter = (HttpRequestAdapter) mOAuthConsumer.sign(request);
requestToSend = (Request) signedAdapter.unwrap();
} catch (OAuthMessageSignerException | OAuthExpectationFailedException | OAuthCommunicationException e) {
// Fail to sign, ignore
e.printStackTrace();
}
return super.execute(requestToSend);
}
}
The signpost-retrofit plugin can be found here: https://github.com/pakerfeldt/signpost-retrofit
public class RetrofitHttpOAuthConsumer extends AbstractOAuthConsumer {
private static final long serialVersionUID = 1L;
public RetrofitHttpOAuthConsumer(String consumerKey, String consumerSecret) {
super(consumerKey, consumerSecret);
}
#Override
protected HttpRequest wrap(Object request) {
if (!(request instanceof retrofit.client.Request)) {
throw new IllegalArgumentException("This consumer expects requests of type " + retrofit.client.Request.class.getCanonicalName());
}
return new HttpRequestAdapter((Request) request);
}
}
Any help here would be great. The solution doesn't have to include the use of signpost but I do want to use Retrofit. I also do not want to show the user an 'Authenticate with Twitter' screen in a WebView - I simply want to display a handful of relevant tweets as part of a detail view.
Are you certain the signpost-retrofit project works for twitter oauth? I've used twitter4j successfully in the past - and if you don't want the full library you can use their code for reference. twitter4j
I am following this tutorial on uploading files to a server from android, but I cannot seem to get the code right on the server side. Can somebody please help me code the Web Api post method that would work with that android java uploader? My current web api controller class looks like this:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;
namespace WSISWebService.Controllers
{
public class FilesController : ApiController
{
// GET api/files
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/files/5
public string Get(int id)
{
return "value";
}
// POST api/files
public string Post([FromBody]string value)
{
var task = this.Request.Content.ReadAsStreamAsync();
task.Wait();
Stream requestStream = task.Result;
try
{
Stream fileStream = File.Create(HttpContext.Current.Server.MapPath("~/" + value));
requestStream.CopyTo(fileStream);
fileStream.Close();
requestStream.Close();
}
catch (IOException)
{
// throw new HttpResponseException("A generic error occured. Please try again later.", HttpStatusCode.InternalServerError);
}
HttpResponseMessage response = new HttpResponseMessage();
response.StatusCode = HttpStatusCode.Created;
return response.ToString();
}
// PUT api/files/5
public void Put(int id, [FromBody]string value)
{
}
// DELETE api/files/5
public void Delete(int id)
{
}
}
}
I am pretty desperate to get this working as the deadline is tuesday. If anybody could help that would be much appreciated.
you can post a files as multipart/form-data
// POST api/files
public async Task<HttpResponseMessage> Post()
{
// Check if the request contains multipart/form-data.
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
string root = HttpContext.Current.Server.MapPath("~/App_Data");
var provider = new MultipartFormDataStreamProvider(root);
string value;
try
{
// Read the form data and return an async data.
var result = await Request.Content.ReadAsMultipartAsync(provider);
// This illustrates how to get the form data.
foreach (var key in provider.FormData.AllKeys)
{
foreach (var val in provider.FormData.GetValues(key))
{
// return multiple value from FormData
if (key == "value")
value = val;
}
}
if (result.FileData.Any())
{
// This illustrates how to get the file names for uploaded files.
foreach (var file in result.FileData)
{
FileInfo fileInfo = new FileInfo(file.LocalFileName);
if (fileInfo.Exists)
{
//do somthing with file
}
}
}
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, value);
response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = files.Id }));
return response;
}
catch (System.Exception e)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
}
}