Spring Webflux : Send JSON in form-url-encoded form without encoding - jetty

Is it possible to send a form-url-encoded request with json in payload without actually encoding json ? Payload is of form jData=json.
I have tried various combination of form headers and BodyInserters, but it is not working, some time content header is wrong, other times body itself is totally JSON which again at the server API level is not desirable.
I have tried to overwrite request content in onRequestContent method in comment piece of code, hoping with this interception I would be able to override request, but still body is not changed.
Please help.
public class FinvasiaAuthenticationProvider implements BrokerAuthenticationProvider {
private static Logger LOGGER = LoggerFactory.getLogger(FinvasiaAuthenticationProvider.class);
private final WebClient client;
private final FinvasiaProperties properties;
private final ObjectMapper mapper;
public FinvasiaAuthenticationProvider(FinvasiaProperties properties,
ObjectMapper mapper) {
this.client = this.jettyHttpClient();
this.properties = properties;
this.mapper = mapper;
}
#Override
public Mono<BrokerAuthentication> authenticate(BrokerAuthenticationRequest req) {
if (!(req instanceof FinvasiaAuthenticationRequest)) {
return Mono.error(IllegalArgumentException::new);
}
var endpoint = String.format("%s/%s", properties.baseUrl(), FinvasiaUrls.LOGIN_URL.url());
var payload = new FinvasiaAuthenticationRequestAdapter(((FinvasiaAuthenticationRequest) req));
String json;
try {
json = mapper.writeValueAsString(payload);
} catch (JsonProcessingException e) {
return Mono.error(e);
}
var hello = "Hello";
Map<String, String> map = new HashMap<>();
map.put("jData", json);
return client.post()
.uri(endpoint)
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE)
.body(BodyInserters.fromFormData("jData", json))
.retrieve()
.onStatus(HttpStatus::is4xxClientError, clientResponse -> {
clientResponse.bodyToMono(String.class).log().subscribe();
return Mono.error(IllegalArgumentException::new);
})
.bodyToMono(String.class)
.map(response -> {
return new FinvasiaAuthentication("1234", Arrays.asList());
});
}
private Request enhance(Request inboundRequest) {
StringBuilder log = new StringBuilder();
inboundRequest.onRequestBegin(request -> log.append("Request: \n")
.append("URI: ")
.append(request.getURI())
.append("\n")
.append("Method: ")
.append(request.getMethod()));
inboundRequest.onRequestHeaders(request -> {
log.append("\nRequest Headers:\n");
for (HttpField header : request.getHeaders()) {
log.append("\n" + header.getName() + ":" + header.getValue());
}
log.append("\n\n");
});
// inboundRequest.onRequestContent((request, content) -> {
//
//
// String b = StandardCharsets.UTF_8.decode(content).toString();
// String[] parts = StringUtils.split(b, '=');
// String decoded = UriUtils.decode(parts[1], StandardCharsets.UTF_8);
//
// content.clear();
// content.put(String.format("%s=%s", parts[0],decoded ).getBytes(StandardCharsets.UTF_8));
//
// request.content(n)
//
// });
inboundRequest.onRequestContent((request, content) ->
log.append("Body: \n\t")
.append(StandardCharsets.UTF_8.decode(content)));
log.append("\n");
inboundRequest.onResponseBegin(response -> {
log.append("Response:\n")
.append("Status: ")
.append(response.getStatus())
.append("\n");
});
inboundRequest.onResponseHeaders(response -> {
log.append("\nResponse Headers:\n");
for (HttpField header : response.getHeaders()) {
log.append("\n" + header.getName() + ":" + header.getValue());
}
log.append("\n\n");
});
inboundRequest.onResponseContent((respones, content) -> {
var bufferAsString = StandardCharsets.UTF_8.decode(content).toString();
log.append("Response Body:\n" + bufferAsString);
});
LOGGER.info("HTTP -> \n");
inboundRequest.onRequestSuccess(request -> LOGGER.info(log.toString()));
inboundRequest.onResponseSuccess(response -> LOGGER.info(log.toString()));
inboundRequest.onResponseFailure((response, throwable) -> LOGGER.info(log.toString()));
return inboundRequest;
}
public WebClient jettyHttpClient() {
SslContextFactory.Client sslContextFactory = new SslContextFactory.Client();
HttpClient httpClient = new HttpClient(sslContextFactory) {
#Override
public Request newRequest(URI uri) {
Request request = super.newRequest(uri);
return enhance(request);
}
};
return WebClient.builder().clientConnector(new JettyClientHttpConnector(httpClient))
// .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE)
.build();
}
}

Related

Pass field from Droid project to PCL, Xamarin.Forms

I have an app that allows users to log in via facebook, once user enters their credentials - My api request saves the user onto the database and auto-generates a user token(This is unique to each user). In order to display user specific details once user logs in - the token needs to be referenced. I am trying to get this token to the PCL project but it returns null just for the token. When I tried passing another string like name, it passes the correct value. Any help will be much appreciated.Thanks
FacebookRender in droid:
public class FacebookRender : PageRenderer
{
public FacebookRender()
{
CustomerService customerService = new CustomerService();
String error;
var activity = this.Context as Activity;
var auth = new OAuth2Authenticator(
clientId: "",
scope: "",
authorizeUrl: new Uri("https://www.facebook.com/dialog/oauth/"),
redirectUrl: new Uri("https://www.facebook.com/connect/login_success.html")
);
auth.Completed += async (sender, eventArgs) =>
{
try
{
if (eventArgs.IsAuthenticated)
{
await AccountStore.Create().SaveAsync(eventArgs.Account, "FacebookProviderKey");
var accessToken = eventArgs.Account.Properties["access_token"].ToString();
var expiresIn = Convert.ToDouble(eventArgs.Account.Properties["expires_in"]);
var expiryDate = DateTime.Now + TimeSpan.FromSeconds(expiresIn);
var request = new OAuth2Request("GET", new Uri("https://graph.facebook.com/me?fields=email,first_name,last_name,gender,picture"), null, eventArgs.Account);
var response = await request.GetResponseAsync();
var obj = JObject.Parse(response.GetResponseText());
var id = obj["id"].ToString().Replace("\"", "");
var name = obj["first_name"].ToString().Replace("\"", "");
var surname = obj["last_name"].ToString().Replace("\"", "");
var gender = obj["gender"].ToString().Replace("\"", "");
//var email = obj["email"].ToString().Replace("\"", "");
Customer.Customers cust = new Customer.Customers();
cust.Credentials = new Customer.Credentials();
cust.Name = name;
cust.Surname = surname;
cust.Email = "";
cust.MobilePhone = "";
cust.DOB = DateTime.Now;
cust.Number = "";
cust.City = "";
cust.Region = "";
cust.Country = "";
cust.DeviceToken = "sample";
cust.Credentials.SecretKey = "";
await customerService.AddCustomer(cust);
App.SaveToken(cust.Credentials.Token); - **//This is where I am passing the token**
App.NavigateToProfile(string.Format(name + surname));
}
else
{
App.NavigateToProfile("Invalid Login");
}
}
catch(Exception ex)
{
error = ex.Message;
}
};
activity.StartActivity(auth.GetUI(activity));
}
App.cs
public App()
{
InitializeComponent();
MainPage = new NavigationPage(new MainPage());
}
public static void NavigateToProfile(string message)
{
App.Current.MainPage = (new Profile(message));
}
static string _Token;
public static string Token
{
get { return _Token; }
}
public static void SaveToken(string token)
{
_Token = token;
}
AboutPage.cs - I am passing the token in a label just to see if it's passing
public partial class About : ContentPage
{
private Label _lbltoken;
public About()
{
//InitializeComponent();
Appearing += (object s, EventArgs a) => {
_lbltoken.Text = App.Token;
};
string tk = App.Token;
_lbltoken = new Label()
{
FontSize = 20,
HorizontalOptions = LayoutOptions.CenterAndExpand,
Text = tk,
};
var stack = new StackLayout
{
VerticalOptions = LayoutOptions.StartAndExpand,
Children = { _lbltoken },
};
Content = stack;
}
}
You can use the MessagingCenter.
Messages may be sent as a result like a button click, a system event or some other incident. Subscribers might be listening in order to change the appearance of the user interface, save data or trigger some other operation.
More Info
I don't really now if its good idea use static fields in App class. Xamarin access all fields with service locator, App.Current.[property] I will suggest you try to change these fields to public
string _Token;
public string Token
{
get { return _Token; }
}
public void SaveToken(string token)
{
_Token = token;
}
and use it with App.Current.SaveToken(token) or App.Current.Token

Retrieving cookies from httprequest in Xamarin.forms

help me, i couldn't get the cookies from an httprequest, i tried the plugins.settings, i tried the pcl share too, am in this problem for a month
public async Task<bool> PostAsync(AuthUser user)
{
var CookieContainer = new CookieContainer();
var handler = new HttpClientHandler() { CookieContainer =
CookieContainer };
var _client = new HttpClient(handler);
IEnumerable<string> cookieStrings = null;
//var httpClient = new HttpClient();
_client.DefaultRequestHeaders.Accept.Add(new
MediaTypeWithQualityHeaderValue("application/json"));
var json = JsonConvert.SerializeObject(user);
HttpContent httpContent = new StringContent(json);
httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
try
{
string url = WebServiceUrl + "j_spring_security_check?j_username=" + user.j_username +"&j_password=" + user.j_password + "&ajax=true";
HttpResponseMessage result = await _client.PostAsync(url, httpContent);
IEnumerable<string> cookies;
if (result.Headers.TryGetValues("set-cookie", out cookies))
{
foreach (var c in cookies)
{
await App.Current.MainPage.DisplayAlert("Cookie", c , "OK");
}
}
if (result.IsSuccessStatusCode)
{
using (var responsecontent = result.Content)
{
string resultString = responsecontent.ReadAsStringAsync().Result;
var response = JsonConvert.DeserializeObject<AuthUser>(resultString);
if (response.error != null)
{
await App.Current.MainPage.DisplayAlert("Error", response.result.error, "OK");
return false;
}
else if (response.result.success.Equals("1"))
{
App.Current.MainPage = new NavigationPage(new TimelineMenuPage(response.result.user_id.ToString(), response.result.token));
return true;
}
}
}
return result.IsSuccessStatusCode;
}
catch (Exception e)
{
await App.Current.MainPage.DisplayAlert("Alert", e.ToString(), "OK");
throw;
}
}
when debugging it skips this part :
if (result.Headers.TryGetValues("set-cookie", out cookies))
{
foreach (var c in cookies)
{
await App.Current.MainPage.DisplayAlert("Cookie", c , "OK");
}
}
**and then i get in CookieContainer count=0 **
Since you are already using a CookieContainer, and you will know the Uri you are getting them from, why don't you just get the Cookies directly from the Container, instead of a set-cookie command, that you will then have to parse.
cookieContainer.GetCookies(new Uri("mydomain.com"));
After your HttpRequest, it will automatically put them into the CookieContainer.

Xamarin Async and Await: UI thread is getting blocked

I have this architecture in my project and sometimes UI thread is getting blocked, can someone please explain what is happening with the below code. Thanks
I am making a service call asyncronously from xamarin.forms viewmodel
Following is the flow
View--->ViewModel---ClassA--->ClassB--Make a service call from here
Code
Scenario 1
public partial class HomePage : ContentPage
{
private HomeVM model;
public HomePage()
{
InitializeComponent();
model = new HomeVM();
model.MainText = ReturnBool().Result;
this.BindingContext = model;
}
public async Task<string> ReturnBool()
{
IsBusy = true;
var r = await new WS().ReturnBool();
IsBusy = false;---------------------------------------Not hitting the breakpoint here
return r;
}
}
public interface IWS
{
Task<string> ReturnBool();
}
public class WS : IWS
{
public Task<string> ReturnBool()
{
return ServiceOperations.ReturnBool();
}
}
internal class ServiceOperations
{
public async static Task<string> ReturnBool()
{
var uri = new Uri(string.Format("http://testmyapi.azurewebsites.net/", string.Empty));
try
{
HttpClient client = new HttpClient();
client.BaseAddress = uri;
HttpResponseMessage response = null;
response = await client.GetAsync("/api/Values/Get");
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
string str = JsonConvert.DeserializeObject<string>(content);
return str;
}
else {
return null;
}
}
catch (Exception)
{
return null;
}
}
}
Scenario 2
public partial class HomePage : ContentPage
{
private HomeVM model;
public HomePage()
{
InitializeComponent();
model = new HomeVM();
this.BindingContext = model;
}
}
public class HomeVM : BaseVM
{
private string mainText;
public string MainText
{
get { return mainText; }
set
{
mainText = value;
RaisePropertyChanged("MainText");
}
}
public HomeVM()
{
MainText = ReturnBool().Result;
}
public async Task<string> ReturnBool()
{
IsBusy = true;
var r = await new WS().ReturnBool();
IsBusy = false;---------------------------------------Not hitting the breakpoint here
return r;
}
}
public interface IWS
{
Task<string> ReturnBool();
}
public class WS : IWS
{
public Task<string> ReturnBool()
{
return ServiceOperations.ReturnBool();
}
}
internal class ServiceOperations
{
public async static Task<string> ReturnBool()
{
var uri = new Uri(string.Format("http://testmyapi.azurewebsites.net/", string.Empty));
try
{
HttpClient client = new HttpClient();
client.BaseAddress = uri;
HttpResponseMessage response = null;
response = await client.GetAsync("/api/Values/Get");
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
string str = JsonConvert.DeserializeObject<string>(content);
return str;
}
else {
return null;
}
}
catch (Exception)
{
return null;
}
}
}
You are using ReturnBool().Result in the constructor. The return call will block your UI thread. Move that code to the controller action methods without using ".Result" part. Ensure that the methods are async and always return a Task.

How to unit test a method with HttpWebRequest/Response dependencies

Been trying to unit test this method but can't figure out how to do it.
public bool ValidateCaptcha(string captchaResponse, string captchaChallenge,
string hostip)
{
var strPrivateKey = _secConfiguration.CaptchaPrivateKey;
var strParameters = "verify?privatekey=" + strPrivateKey +
"&remoteip=" + hostip +
"&challenge=" + captchaChallenge+
"&response=" + captchaResponse;
var url = CaptchaUrl + strParameters;
var request = CreateHttpWebRequest(url);
request.Proxy.Credentials = CredentialCache.DefaultCredentials;
request.Method = "POST";
request.ContentType = "text/html";
request.ContentLength = 0;
var response = GetHttpWebResponse(request);
var writer = response.GetResponseStream();
var reader = new StreamReader(writer);
var responseFromServer = reader.ReadToEnd();
var serverResponse = responseFromServer.Split('\n');
return serverResponse[0] == "true";
}
private HttpWebResponse GetHttpWebResponse(HttpWebRequest request)
{
return (HttpWebResponse) request.GetResponse();
}
private HttpWebRequest CreateHttpWebRequest(string url)
{
return (HttpWebRequest) WebRequest.Create(url);
}
I had planned to moq the dependencies and have a couple of wrap classes
public class WrapHttpWebRequest : IHttpWebRequest
{
private readonly HttpWebRequest _request;
public WrapHttpWebRequest(HttpWebRequest request)
{
_request = request;
}
public string Method
{
get { return _request.Method; }
set { _request.Method = value; }
}
public IHttpWebResponse GetResponse()
{
return new WrapHttpWebResponse((HttpWebResponse)_request.GetResponse());
}
}
and
public class WrapHttpWebResponse : IHttpWebResponse
{
private WebResponse _response;
public WrapHttpWebResponse(HttpWebResponse response)
{
_response = response;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (disposing)
{
if (_response != null)
{
((IDisposable)_response).Dispose();
_response = null;
}
}
}
public Stream GetResponseStream()
{
return _response.GetResponseStream();
}
}
But can't find a way to inject them. Any ideas how can I do this? Thanks.
You could create testable version of your class under test.
Make the method virtual and override it in the testable version.
protected virtual HttpWebRequest CreateHttpWebRequest(string url)
{
return (HttpWebRequest)WebRequest.Create(url);
}
public class TesableClassUnderTest : ClassUnderTest
{
public HttpWebRequest HttpWebRequestFake { get; set; }
protected override HttpWebRequest CreateHttpWebRequest(string url)
{
if (HttpWebRequestFake != null)
return HttpWebRequestFake;
return base.CreateHttpWebRequest(url);
}
}
Then in test set the fake object to your own value:
[TestMethod]
public void test()
{
TesableClassUnderTest cut = new TesableClassUnderTest();
cut.HttpWebRequestFake = CreateFakeHttpWebRequest();
cut.ValidateCaptcha(...)
Assert...
}

Is it possible to unit test BundleConfig in MVC4?

As far as I can tell, the answer is no. The issue I'm seeing comes from the Include(params string[]) method in the System.Web.Optimization.Bundle class. Internally this invokes System.Web.Optimization.IncludeDirectory(string, string, bool), which in turn uses this code:
DirectoryInfo directoryInfo = new DirectoryInfo(
HttpContext.Current.Server.MapPath(directoryVirtualPath));
While it is possible to set HttpContext.Current during a unit test, I can't figure out how to make its .Server.MapPath(string directoryVirtualPath) return a non-null string. Since the DirectoryInfo(string) constructor throws an exception when passed a null argument, such a test will always fail.
What is the .NET team's recommendation for this? Do we have to unit test bundling configurations as part of integration tests or user acceptance tests?
I have some good news for you, for RTM we added a new static property on BundleTable to enable more unit tests:
public static Func<string, string> MapPathMethod;
Edit Updated with a test virtual path provider:
So you can do something like this:
public class TestVirtualPathProvider : VirtualPathProvider {
private string NormalizeVirtualPath(string virtualPath, bool isDirectory = false) {
if (!virtualPath.StartsWith("~")) {
virtualPath = "~" + virtualPath;
}
virtualPath = virtualPath.Replace('\\', '/');
// Normalize directories to always have an ending "/"
if (isDirectory && !virtualPath.EndsWith("/")) {
return virtualPath + "/";
}
return virtualPath;
}
// Files on disk (virtualPath -> file)
private Dictionary<string, VirtualFile> _fileMap = new Dictionary<string, VirtualFile>();
private Dictionary<string, VirtualFile> FileMap {
get { return _fileMap; }
}
public void AddFile(VirtualFile file) {
FileMap[NormalizeVirtualPath(file.VirtualPath)] = file;
}
private Dictionary<string, VirtualDirectory> _directoryMap = new Dictionary<string, VirtualDirectory>();
private Dictionary<string, VirtualDirectory> DirectoryMap {
get { return _directoryMap; }
}
public void AddDirectory(VirtualDirectory dir) {
DirectoryMap[NormalizeVirtualPath(dir.VirtualPath, isDirectory: true)] = dir;
}
public override bool FileExists(string virtualPath) {
return FileMap.ContainsKey(NormalizeVirtualPath(virtualPath));
}
public override bool DirectoryExists(string virtualDir) {
return DirectoryMap.ContainsKey(NormalizeVirtualPath(virtualDir, isDirectory: true));
}
public override VirtualFile GetFile(string virtualPath) {
return FileMap[NormalizeVirtualPath(virtualPath)];
}
public override VirtualDirectory GetDirectory(string virtualDir) {
return DirectoryMap[NormalizeVirtualPath(virtualDir, isDirectory: true)];
}
internal class TestVirtualFile : VirtualFile {
public TestVirtualFile(string virtualPath, string contents)
: base(virtualPath) {
Contents = contents;
}
public string Contents { get; set; }
public override Stream Open() {
return new MemoryStream(UTF8Encoding.Default.GetBytes(Contents));
}
}
internal class TestVirtualDirectory : VirtualDirectory {
public TestVirtualDirectory(string virtualPath)
: base(virtualPath) {
}
public List<VirtualFile> _directoryFiles = new List<VirtualFile>();
public List<VirtualFile> DirectoryFiles {
get {
return _directoryFiles;
}
}
public List<VirtualDirectory> _subDirs = new List<VirtualDirectory>();
public List<VirtualDirectory> SubDirectories {
get {
return _subDirs;
}
}
public override IEnumerable Files {
get {
return DirectoryFiles;
}
}
public override IEnumerable Children {
get { throw new NotImplementedException(); }
}
public override IEnumerable Directories {
get {
return SubDirectories;
}
}
}
And then write a unit test using that like so:
[TestMethod]
public void StyleBundleCustomVPPIncludeVersionSelectsTest() {
//Setup the vpp to contain the files/directories
TestVirtualPathProvider vpp = new TestVirtualPathProvider();
var directory = new TestVirtualPathProvider.TestVirtualDirectory("/dir/");
directory.DirectoryFiles.Add(new TestVirtualPathProvider.TestVirtualFile("/dir/style1.0.css", "correct"));
directory.DirectoryFiles.Add(new TestVirtualPathProvider.TestVirtualFile("/dir/style.css", "wrong"));
vpp.AddDirectory(directory);
// Setup the bundle
ScriptBundle bundle = new ScriptBundle("~/bundles/test");
bundle.Items.VirtualPathProvider = vpp;
bundle.Include("~/dir/style{version}.css");
// Verify the bundle repsonse
BundleContext context = SetupContext(bundle, vpp);
BundleResponse response = bundle.GetBundleResponse(context);
Assert.AreEqual(#"correct", response.Content);
}
In .Net 4.5 things have slightly changed. Here is a working version of the approved answer updated to accommodate these changes (I am using Autofac). Note the "GenerateBundleResponse" instead of "GetBundleResponse":
[Fact]
public void StyleBundleIncludesVersion()
{
//Setup the vpp to contain the files/directories
var vpp = new TestVirtualPathProvider();
var directory = new TestVirtualPathProvider.TestVirtualDirectory("/dir/");
directory.DirectoryFiles.Add(new TestVirtualPathProvider.TestVirtualFile("/dir/style1.0.css", "correct"));
directory.DirectoryFiles.Add(new TestVirtualPathProvider.TestVirtualFile("/dir/style.css", "wrong"));
vpp.AddDirectory(directory);
// Setup the bundle
var bundleCollection = new BundleCollection();
var bundle = new ScriptBundle("~/bundles/test");
BundleTable.VirtualPathProvider = vpp;
bundle.Include("~/dir/style{version}.css");
bundleCollection.Add(bundle);
var mockHttpContext = new Mock<HttpContextBase>();
// Verify the bundle repsonse
var context = new BundleContext(mockHttpContext.Object, bundleCollection, vpp.ToString());
var response = bundle.GenerateBundleResponse(context);
Assert.Equal(#"correct", response.Content);
}