In my kotlin project, I use retrofit and it works well.
suspend fun createPlan(
context: Context?,
name: String,
file: File?
): ABC? {
val fileSignImage = file?.let {
MultipartBody.Part.createFormData(
"image",
it.getName(),
RequestBody.create("image/*".toMediaTypeOrNull(), it)
)
}
return RetrofitFactory.apiCall(context) {
RetrofitFactory.makeRetrofitService().createPlan(
name.toRequestBody("text/plain".toMediaTypeOrNull()),
fileSignImage
)
}}
RetrofitService
#Multipart
#POST("create_plan")
fun createPlan(
#Part("name") name: RequestBody,
#Part image: MultipartBody.Part?
): Deferred<Response<WebApiResponse.ABCs>>
If I want to use Chopper, what is the correct way?
This is what I have tried
Future<Response> createPlan(
BuildContext context, String name,String path) async {
Response response;
try {
response = await _service.createPlan(
name,path);
return response;
} catch (e) {
rethrow;
}
}
Service
#Post(path: "create_plan")
#multipart
Future<Response> createPlan(
#Field('name') String name,#PartFile('image') String imagePath);
How can I convert the imagePath to file so I can pass it as file to server using Chopper?
Anyone?
Looking at the documentation for Chopper, the PartFile annotation supports three data types:
List<int>
String (path of your file)
MultipartFile (from package:http)
You are currently using String, but for reasons unknown it is not working for you. The first option would probably be the most straightforward, but the third option would be the most similar to what you currently have in Retrofit, so we could try that.
import 'package:http/http.dart';
...
Future<Response> createPlan(BuildContext context, String name, String path) async {
Response response;
try {
final bytes = (await File(path).readAsBytes()).toList();
final file = MultipartFile.fromBytes('image', bytes);
response = await _service.createPlan(
name,
file,
);
return response;
} catch (e) {
rethrow;
}
}
Service
#Post(path: "create_plan")
#multipart
Future<Response> createPlan(
#Field('name') String name,
#PartFile('image') MultipartFile image,
);
I was managed to upload file using http instead of Chopper.
Future<http.Response> createPlan(String name, String path) async {
var request = http.MultipartRequest(
"POST",
Uri.parse(
"http://xxx"));
request.fields['name'] = name;
request.files.add(await http.MultipartFile.fromPath(
'image',
path,
));
try {
var streamedResponse = await request.send();
var response = http.Response.fromStream(streamedResponse);
return response;
} catch (e) {
rethrow;
}
}
Related
Is it possible to send graphQL queries with the standard httpclient in .NET core?
When I try to send my query with a client.post I get "Expected { or [ as first syntax token."
How can I send GraphQL queries with a httpclient.
Without having to use a library (like GraphQLHttpClient etc..)
Got it:
Just add "query" as a json object. Like this:
{"query" : "query { __schema { queryType { name } mutationType { name } types { name } directives { name } } }"}
In .NET you can use this in an HTTP post (don't forget to string escape the double quotes
private static string myquery = "{ \"query\" : \"query { __schema { queryType { name } mutationType { name } types { name } directives { name } } }\" }";
Here's an example of how to call a GraphQL endpoint with HttpClient in .net Core:
public async Task<string> GetProductsData(string userId, string authToken)
{
var httpClient = new HttpClient
{
BaseAddress = new Uri(_apiUrl)
};
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authToken);
var queryObject = new
{
query = #"query Products {
products {
id
description
title
}
}",
variables = new { where = new { userId = userId } }//you can add your where cluase here.
};
var request = new HttpRequestMessage
{
Method = HttpMethod.Post,
Content = new StringContent(JsonConvert.SerializeObject(queryObject), Encoding.UTF8, "application/json")
};
using (var response = await httpClient.SendAsync(request))
{
response.EnsureSuccessStatusCode();
var responseString = await response.Content.ReadAsStringAsync();
return responseString;
}
}
I am trying to save some info in the userStorage in Kotlin
In javascript, I did the following
exports.saveFloor = (conv, floor) => {
conv.user.storage.floor = floor;
}
here is the client library
From Name Psychic:
#ForIntent("request_name_permission")
public ActionResponse requestNamePermission(ActionRequest request) {
ResponseBuilder response = getResponseBuilder(request);
String requestedPermission = ConstantsKt.PERMISSION_NAME;
response.getConversationData().put(DATA_KEY_REQUESTED_PERMISSION, requestedPermission);
String storageKey = STORAGE_KEY_NAME;
if (!request.getUserStorage().containsKey(storageKey)) {
Permission permission =
new Permission()
.setContext(formatResponse("permission_reason"))
.setPermissions(new String[] {requestedPermission});
response.add("PLACEHOLDER_FOR_PERMISSION");
response.add(permission);
} else {
String name = (String) request.getUserStorage().get(storageKey);
response.add(formatResponse("say_name", name));
response.endConversation();
}
return response.build();
}
I guess the snippet I was looking for is
Map<String, Object> storage = response.getUserStorage();
String requestedPermission =
(String) request.getConversationData().get(DATA_KEY_REQUESTED_PERMISSION);
if (requestedPermission.equals(ConstantsKt.PERMISSION_NAME)) {
String name = request.getUser().getProfile().getDisplayName();
storage.put(STORAGE_KEY_NAME, name);
response.add(formatResponse("say_name", name));
response.endConversation();
return response.build();
}
if (requestedPermission.equals(ConstantsKt.PERMISSION_DEVICE_COARSE_LOCATION)) {
String location = request.getDevice().getLocation().getCity();
storage.put(STORAGE_KEY_LOCATION, location);
showLocationOnScreen(request, response);
return response.build();
}
The equivalent of my javascript code into Kotlin would be
fun saveFloor(request: ActionRequest, floor: String) {
val response = getResponseBuilder(request)
val storage = response.userStorage as MutableMap
storage["floor"] = floor
}
Cheers to Nick for pointing me in the right direction
I am working on a MVC project that submits a request via a third party.
In my controller, I have a SubmitClaims() action that receive ajax request and then calls RunAsync(). RunAsync submits a request by using HttpClient.
I am not sure if I did a right thing here.
Also I have two version of SubmitClaims(), both work. But I don't know which version is better.
version 1
[HttpPost]
public async Task<string> SubmitClaims()
{
string result = "";
result = await RunAsync();
return result;
}
version 2 learn from Cannot implicitly convert type 'string' to 'System.Threading.Tasks.Task<string>'
[HttpPost]
public async Task<string> SubmitClaims()
{
return await Task.Run(() =>
{
return RunAsync();
});
}
static async Task<string> RunAsync()
{
string result = "Failed.";
using (var client = new HttpClient())
{
try
{
client.BaseAddress = new Uri("http://peter:8001/internal/uickpost");
client.DefaultRequestHeaders.Add("contenttype", "application/xml");
client.DefaultRequestHeaders.Add("hiconline.protocol.content.role", "REQUEST");
client.DefaultRequestHeaders.Add("hiconline.protocol.content.transactionid", "asdfsdf");
client.DefaultRequestHeaders.Add("hiconline.protocol.remote.contenttype", "TestDataType");
client.DefaultRequestHeaders.Add("hiconline.protocol.remote.mode", "P");
client.DefaultRequestHeaders.Host = "peter:8001";
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/plain"));
string opv = "Test Data";
HttpContent _content = new StringContent(opv);
_content.Headers.ContentType = new MediaTypeHeaderValue("application/xml");
_content.Headers.Add("contenttype", "TestDataType");
HttpResponseMessage response1 = await client.PostAsync(client.BaseAddress, _content);
if (response1.IsSuccessStatusCode)
{
Uri gizmoUrl = response1.Headers.Location;
result = response1.Content.ReadAsStringAsync().Result;
}
}
catch (Exception ex)
{
result = ex.Message;
}
return result;
}
}
Option 1 is better. RunAsync() already returns a task, so why create another one?
Even better would be return await RunAsync();. Even better would just be calling RunAsync directly, since the wrapper doesn't add anything.
I have a requirement on my web app to save multiple attachments to my SQL server. The attachments can be in any format. Is it possible to create a knockout viewmodel to encode the file type on client side to binary and transferring that binary info to my SQL server?
I currently have this method in my REST service:
[OperationContract, WebInvoke(ResponseFormat = WebMessageFormat.Json)]
public string PostAttachments (string FileName)
{
try
{
var MyAttachment = new Binary(File.ReadAllBytes(FileName));
return "Attachments Created";
}
catch (Exception ex)
{
return DefaultError + ex;
}
}
I know this is incorrect but I am really not sure how to do this file upload. I believe I am over complicating it. Any Assistance would be greatly appreciated.
You will have to transfer the buffer to the server not just the filename, since the file exists on the client.
I used the HTML5 FileReader in my last KO project
First a custom binding to read the file from the DOM element
(function () {
ko.bindingHandlers.file = {
init: function (element, valueAccessor, allBindingsAccessor) {
ko.utils.registerEventHandler(element, "change", function () {
writeValueToProperty(valueAccessor(), allBindingsAccessor, "file", element.files[0]);
});
},
update: function (element, valueAccessor) {
if (ko.utils.unwrapObservable(valueAccessor()) == null) {
element.value = "";
}
}
};
var writeValueToProperty = function (property, allBindingsAccessor, key, value, checkIfDifferent) {
if (!property || !ko.isObservable(property)) {
var propWriters = allBindingsAccessor()['_ko_property_writers'];
if (propWriters && propWriters[key])
propWriters[key](value);
} else if (ko.isWriteableObservable(property) && (!checkIfDifferent || property.peek() !== value)) {
property(value);
}
};
} ());
FileReader usage (code specific for how I used it in my app). Check the FileReader part only.
Note if you have large files you need to stream instead
processFiles: function (viewModel, callback) {
var files = [];
ko.utils.arrayForEach(viewModel.files, function (file) {
if (file.fileUpload() == null) return;
var count = Enumerable.From(viewModel.files)
.Where(function(f) { return f.fileUpload() != null; })
.Count();
var reader = new FileReader();
reader.onload = function (e) {
var base64 = e.target.result.substr(e.target.result.indexOf(",") + 1);
files.push({ Type: file.type, Data: base64, Filename: file.fileUpload().name });
if (files.length == count) {
callback(files);
}
};
reader.readAsDataURL(file.fileUpload());
});
}
Update
Like said this is code for my use case, you will need to change it to fit your purpose
<div data-bind="foreach: files">
<p><label data-bind="text: typeName"></label><input data-bind="file: fileUpload" type="file" /></p>
</div>
Controller (I would use WebApi if I did this today)
public JsonResult UploadFiles(IEnumerable<FileUploadViewModel> uploads)
{
fileRepository.SaveUploadedFiles(Mapper.Map<IEnumerable<FileUploadViewModel>, IEnumerable <FileUpload>> (uploads));
return string.Empty.AsJson();
}
FileUploadViewModel
public class FileUploadViewModel
{
public FileType Type { get; set; }
public string Filename { get; set; }
public string Data { get; set; }
}
Automapper config
Mapper.CreateMap<FileUploadViewModel, FileUpload>()
.ForMember(to => to.Buffer, opt => opt.MapFrom(from => Convert.FromBase64String(from.Data)));
I am writing a unit test to validate the serialization of objects and I am able to successfully save the file without any issue. I can even browse the file and validate the contents are correct. However, when I attempt to open the file for reading I always receive an UnauthorizedAccess exception.
Here is the code used to save the item:
public static async Task SaveItem<T>(string folderName, T item)
where T : BaseBusinessItem
{
if (string.IsNullOrEmpty(folderName))
{
throw new ArgumentNullException("folderName");
}
if (item == null)
{
throw new ArgumentNullException("item");
}
try
{
var folder = await ApplicationData.Current.LocalFolder
.CreateFolderAsync(folderName, CreationCollisionOption.OpenIfExists);
var file =
await
folder.CreateFileAsync(item.UniqueID.GetHashCode().ToString(), CreationCollisionOption.ReplaceExisting);
var stream = await file.OpenAsync(FileAccessMode.ReadWrite);
using (var outStream = stream.GetOutputStreamAt(0))
{
var serializer = new DataContractJsonSerializer(typeof(T));
serializer.WriteObject(outStream.AsStreamForWrite(), item);
await outStream.FlushAsync();
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
}
}
Here is the code used to restore the item:
public static async Task<T> RestoreItem<T>(string folderName, string hashCode)
where T : BaseBusinessItem, new()
{
if (string.IsNullOrEmpty(folderName))
{
throw new ArgumentNullException("folderName");
}
if (string.IsNullOrEmpty(hashCode))
{
throw new ArgumentNullException("hashCode");
}
var folder = await ApplicationData.Current.LocalFolder.GetFolderAsync(folderName);
var file = await folder.GetFileAsync(hashCode);
var inStream = await file.OpenSequentialReadAsync();
var serializer = new DataContractJsonSerializer(typeof(T));
var retVal = (T)serializer.ReadObject(inStream.AsStreamForRead());
return retVal;
}
And the unit test:
[TestMethod]
public async Task TestFileSaveLoad()
{
await _ds.SaveItem("TestFolder");
Guid ID = _item.UniqueID;
_ds = await ItemDataSource.LoadItem("TestFolder", ID.GetHashCode().ToString());
}
Any ideas or troubleshooting steps I might be missing. The unit test app manifest includes the following capabilities: Document Library, Internet (Client). The following declarations are in place: File Open Picker, File Save Picker and File Type Associations.
Thanks!
This code snippet helped me accomplish my goal. Hope this is helpful for someone else:
http://codepaste.net/gtu5mq