i am send data using unitywebrequest but db/server is getting empty json string.
public class Credentials : Singleton<Credentials>
{
public string email;
public string password;
public string ConvertToJason()
{
return JsonUtility.ToJson(this);
}
}
public class LogIn : MonoBehaviour
{
public InputField emailAddress;
public InputField passwordField;
public GameObject loadingCanvas;
public GameObject loginButton;
public GameObject loadingImg;
string Url = "linkName";
public void LoginButton()
{
loginButton.SetActive(false);
loadingImg.SetActive(true);
if (emailAddress.text == "" || passwordField.text == "")
{
Debug.Log("Empty");
loginButton.SetActive(true);
loadingImg.SetActive(false);
}
else
{
Credentials.Instance.email = emailAddress.text.ToString();
Credentials.Instance.password = passwordField.text.ToString();
//StartCoroutine(LogInAuthenticate());
Value = Credentials.Instance.ConvertToJason();
Debug.Log(Value);
StartCoroutine(LogInAuthenticate());
}
loginButton.SetActive(true);
loadingImg.SetActive(false);
}
string Value;
IEnumerator LogInAuthenticate()
{
using (UnityWebRequest www = UnityWebRequest.Post(Url, Value))
{
www.SetRequestHeader("Content-Type", "application/json");
yield return www.SendWebRequest();
if (www.result != UnityWebRequest.Result.Success)
{
Debug.LogError ("Web Issue : "+ www.error);
}
else
{
string responseText = www.downloadHandler.text;
Debug.Log("Log Message : " + responseText);
if (responseText.StartsWith("Authenticate Successfully"))
{
Debug.Log("Sucess :" + responseText);
}
else
{
Debug.LogError("Log Issue : " + responseText);
}
}
}
}
}
php code is working fine on postman application.
all data is being handled in json, i am using unityweb request, and data directly through string, becuase wwwform was not working out quite like what i expected, maybe i didnt understood it.
i think i am missing some headers or maybe its due to syntex, but there not much help on internet about this.
If you use the overload UnityWebRequest.Post(string url, string data) note that
The data in postData will be escaped, then interpreted into a byte stream via System.Text.Encoding.UTF8
In order to avoid this you could rather use
using (UnityWebRequest www = UnityWebRequest(Url, "POST"))
{
var bytes = Encoding.UTF8.GetBytes(Value);
request.uploadHandler = new UploadHandlerRaw(bytes);
request.uploadHandler.contentType = "application/json";
request.downloadHandler = new DownloadHandlerBuffer();
yield return www.SendWebRequest();
....
}
Related
I have sucessfully generated classes from Swagger Definition (Openapi 3.0.3) using nSwag Studio, but I have no idea how to properly use this as a client.
Manually RestSharp code works fine, but I'd like to use autogenerated code to consume webservice methods and can't do it properly
This is working fine:
string clientId = "dev";
string clientSecret = #"pass";
var client = new RestClient("http://192.168.1.10/xyz/api/oauth/token");
var request = new RestRequest(Method.POST);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddHeader("grant_type", "client_credentials");
var credentials = string.Format("{0}:{1}", clientId, clientSecret);
var headerValue = Convert.ToBase64String(Encoding.UTF8.GetBytes(credentials));
request.AddHeader("Authorization", $"Basic {headerValue}");
request.AddParameter($"application/x-www-form-urlencoded", $"grant_type=client_credentials&client_id={clientId}&client_secret{clientSecret}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request, Method.POST);
My try with autogenerated code. My apoligizes if its wrong, but can't find any example.
There's just few examples but looks like client is generated in a different way (client initialization with base url - but still no idea about basic authorization in this context)
Googling returns mostly "How to create server side" or add swagger to asp/mvc/webapi project.
string URL = #"http://192.168.1.10/xyz/api";
string clientId = "dev";
string clientSecret = #"pass";
IO.Swagger.Client.ApiClient client = new IO.Swagger.Client.ApiClient(URL);
IO.Swagger.Client.Configuration.DefaultApiClient = client; //<<this throws error
IO.Swagger.Client.Configuration.Username = clientId;
IO.Swagger.Client.Configuration.Password = clientSecret;
client.AddDefaultHeader("Authorization", "bearer TOKEN");
IO.Swagger.Api.AuthApi authApi = new IO.Swagger.Api.AuthApi(client);
Error in ApiClient class
public ApiClient(String basePath="/xyz/api")
{
BasePath = basePath;
RestClient = new RestClient(BasePath); //System.UriFormatException: 'Invalid URI: The format of the URI could not be determined.'
}
I have tried many string forms of url (class doesn't accept Uri explictly)
Configuration
using System;
using System.Reflection;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace IO.Swagger.Client
{
public class Configuration
{
public const string Version = "1.0.0";
public static ApiClient DefaultApiClient = new ApiClient();
public static String Username { get; set; }
public static String Password { get; set; }
public static Dictionary<String, String> ApiKey = new Dictionary<String, String>();
public static Dictionary<String, String> ApiKeyPrefix = new Dictionary<String, String>();
private static string _tempFolderPath = Path.GetTempPath();
public static String TempFolderPath
{
get { return _tempFolderPath; }
set
{
if (String.IsNullOrEmpty(value))
{
_tempFolderPath = value;
return;
}
// create the directory if it does not exist
if (!Directory.Exists(value))
Directory.CreateDirectory(value);
// check if the path contains directory separator at the end
if (value[value.Length - 1] == Path.DirectorySeparatorChar)
_tempFolderPath = value;
else
_tempFolderPath = value + Path.DirectorySeparatorChar;
}
}
private const string ISO8601_DATETIME_FORMAT = "o";
private static string _dateTimeFormat = ISO8601_DATETIME_FORMAT;
public static String DateTimeFormat
{
get
{
return _dateTimeFormat;
}
set
{
if (string.IsNullOrEmpty(value))
{
// Never allow a blank or null string, go back to the default
_dateTimeFormat = ISO8601_DATETIME_FORMAT;
return;
}
// Caution, no validation when you choose date time format other than ISO 8601
// Take a look at the above links
_dateTimeFormat = value;
}
}
public static String ToDebugReport()
{
String report = "C# SDK (IO.Swagger) Debug Report:\n";
report += " OS: " + Environment.OSVersion + "\n";
report += " .NET Framework Version: " + Assembly
.GetExecutingAssembly()
.GetReferencedAssemblies()
.Where(x => x.Name == "System.Core").First().Version.ToString() + "\n";
report += " Version of the API: 2.0.1\n";
report += " SDK Package Version: 1.0.0\n";
return report;
}
}
}
Client
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text.RegularExpressions;
using System.IO;
using System.Web;
using System.Linq;
using System.Net;
using System.Text;
using Newtonsoft.Json;
using RestSharp;
using RestSharp.Extensions;
namespace IO.Swagger.Client
{
public class ApiClient
{
private readonly Dictionary<String, String> _defaultHeaderMap = new Dictionary<String, String>();
public ApiClient(String basePath="/xyz/api")
{
BasePath = basePath;
RestClient = new RestClient(BasePath);
}
public string BasePath { get; set; }
public RestClient RestClient { get; set; }
public Dictionary<String, String> DefaultHeader
{
get { return _defaultHeaderMap; }
}
public Object CallApi(String path, RestSharp.Method method, Dictionary<String, String> queryParams, String postBody,
Dictionary<String, String> headerParams, Dictionary<String, String> formParams,
Dictionary<String, FileParameter> fileParams, String[] authSettings)
{
var request = new RestRequest(path, method);
UpdateParamsForAuth(queryParams, headerParams, authSettings);
// add default header, if any
foreach(var defaultHeader in _defaultHeaderMap)
request.AddHeader(defaultHeader.Key, defaultHeader.Value);
// add header parameter, if any
foreach(var param in headerParams)
request.AddHeader(param.Key, param.Value);
// add query parameter, if any
foreach(var param in queryParams)
request.AddParameter(param.Key, param.Value, ParameterType.GetOrPost);
// add form parameter, if any
foreach(var param in formParams)
request.AddParameter(param.Key, param.Value, ParameterType.GetOrPost);
// add file parameter, if any
foreach(var param in fileParams)
request.AddFile(param.Value.Name, param.Value.Writer, param.Value.FileName, param.Value.ContentType);
if (postBody != null) // http body (model) parameter
request.AddParameter("application/json", postBody, ParameterType.RequestBody);
return (Object)RestClient.Execute(request);
}
public void AddDefaultHeader(string key, string value)
{
_defaultHeaderMap.Add(key, value);
}
public string EscapeString(string str)
{
return RestSharp.Contrib.HttpUtility.UrlEncode(str);
}
public FileParameter ParameterToFile(string name, Stream stream)
{
if (stream is FileStream)
return FileParameter.Create(name, stream.ReadAsBytes(), Path.GetFileName(((FileStream)stream).Name));
else
return FileParameter.Create(name, stream.ReadAsBytes(), "no_file_name_provided");
}
public string ParameterToString(object obj)
{
if (obj is DateTime)
// Return a formatted date string - Can be customized with Configuration.DateTimeFormat
// Defaults to an ISO 8601, using the known as a Round-trip date/time pattern ("o")
// https://msdn.microsoft.com/en-us/library/az4se3k1(v=vs.110).aspx#Anchor_8
// For example: 2009-06-15T13:45:30.0000000
return ((DateTime)obj).ToString (Configuration.DateTimeFormat);
else if (obj is List<string>)
return String.Join(",", (obj as List<string>).ToArray());
else
return Convert.ToString (obj);
}
public object Deserialize(string content, Type type, IList<Parameter> headers=null)
{
if (type == typeof(Object)) // return an object
{
return content;
}
if (type == typeof(Stream))
{
var filePath = String.IsNullOrEmpty(Configuration.TempFolderPath)
? Path.GetTempPath()
: Configuration.TempFolderPath;
var fileName = filePath + Guid.NewGuid();
if (headers != null)
{
var regex = new Regex(#"Content-Disposition:.*filename=['""]?([^'""\s]+)['""]?$");
var match = regex.Match(headers.ToString());
if (match.Success)
fileName = filePath + match.Value.Replace("\"", "").Replace("'", "");
}
File.WriteAllText(fileName, content);
return new FileStream(fileName, FileMode.Open);
}
if (type.Name.StartsWith("System.Nullable`1[[System.DateTime")) // return a datetime object
{
return DateTime.Parse(content, null, System.Globalization.DateTimeStyles.RoundtripKind);
}
if (type == typeof(String) || type.Name.StartsWith("System.Nullable")) // return primitive type
{
return ConvertType(content, type);
}
// at this point, it must be a model (json)
try
{
return JsonConvert.DeserializeObject(content, type);
}
catch (IOException e)
{
throw new ApiException(500, e.Message);
}
}
public string Serialize(object obj)
{
try
{
return obj != null ? JsonConvert.SerializeObject(obj) : null;
}
catch (Exception e)
{
throw new ApiException(500, e.Message);
}
}
public string GetApiKeyWithPrefix (string apiKeyIdentifier)
{
var apiKeyValue = "";
Configuration.ApiKey.TryGetValue (apiKeyIdentifier, out apiKeyValue);
var apiKeyPrefix = "";
if (Configuration.ApiKeyPrefix.TryGetValue (apiKeyIdentifier, out apiKeyPrefix))
return apiKeyPrefix + " " + apiKeyValue;
else
return apiKeyValue;
}
public void UpdateParamsForAuth(Dictionary<String, String> queryParams, Dictionary<String, String> headerParams, string[] authSettings)
{
if (authSettings == null || authSettings.Length == 0)
return;
foreach (string auth in authSettings)
{
// determine which one to use
switch(auth)
{
case "BasicAuth":
headerParams["Authorization"] = "Basic " + Base64Encode(Configuration.Username + ":" + Configuration.Password);
break;
case "BearerAuth":
break;
default:
//TODO show warning about security definition not found
break;
}
}
}
public static string Base64Encode(string text)
{
var textByte = System.Text.Encoding.UTF8.GetBytes(text);
return System.Convert.ToBase64String(textByte);
}
public static Object ConvertType(Object fromObject, Type toObject) {
return Convert.ChangeType(fromObject, toObject);
}
}
}
AuthApi
using System;
using System.Collections.Generic;
using RestSharp;
using IO.Swagger.Client;
using IO.Swagger.Model;
namespace IO.Swagger.Api
{
public interface IAuthApi
{
InlineResponse200 OauthTokenPost (string grantType);
}
public class AuthApi : IAuthApi
{
public AuthApi(ApiClient apiClient = null)
{
if (apiClient == null) // use the default one in Configuration
this.ApiClient = Configuration.DefaultApiClient;
else
this.ApiClient = apiClient;
}
public AuthApi(String basePath)
{
this.ApiClient = new ApiClient(basePath);
}
public void SetBasePath(String basePath)
{
this.ApiClient.BasePath = basePath;
}
public String GetBasePath(String basePath)
{
return this.ApiClient.BasePath;
}
public ApiClient ApiClient {get; set;}
public InlineResponse200 OauthTokenPost (string grantType)
{
var path = "/oauth/token";
path = path.Replace("{format}", "json");
var queryParams = new Dictionary<String, String>();
var headerParams = new Dictionary<String, String>();
var formParams = new Dictionary<String, String>();
var fileParams = new Dictionary<String, FileParameter>();
String postBody = null;
if (grantType != null) formParams.Add("grant_type", ApiClient.ParameterToString(grantType)); // form parameter
// authentication setting, if any
String[] authSettings = new String[] { "BasicAuth" };
// make the HTTP request
IRestResponse response = (IRestResponse) ApiClient.CallApi(path, Method.POST, queryParams, postBody, headerParams, formParams, fileParams, authSettings);
if (((int)response.StatusCode) >= 400)
throw new ApiException ((int)response.StatusCode, "Error calling OauthTokenPost: " + response.Content, response.Content);
else if (((int)response.StatusCode) == 0)
throw new ApiException ((int)response.StatusCode, "Error calling OauthTokenPost: " + response.ErrorMessage, response.ErrorMessage);
return (InlineResponse200) ApiClient.Deserialize(response.Content, typeof(InlineResponse200), response.Headers);
}
}
}
I am under impression that your main problem is Uri formating. I would suggest finding the exact problem by doing
string URL = #"http://192.168.1.10/xyz/api";
Uri baseAddress = new Uri(URL);
string clientId = "dev";
string clientSecret = #"pass";
IO.Swagger.Client.ApiClient client = new IO.Swagger.Client.ApiClient(baseAddress.ToString());
IO.Swagger.Client.Configuration.DefaultApiClient = client; //<<this throws error
IO.Swagger.Client.Configuration.Username = clientId;
IO.Swagger.Client.Configuration.Password = clientSecret;
client.AddDefaultHeader("Authorization", "bearer TOKEN");
IO.Swagger.Api.AuthApi authApi = new IO.Swagger.Api.AuthApi(client);
I'm making a quiz game and I'm stuck at this problem that is probably easy to do.
I have this script, which gets JSON data from server and separates it:
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Networking;
using System;
using TMPro;
[Serializable]
public class RootObject
{
public Results[] Result;
}
[Serializable]
public class Results
{
public string id;
public string question;
public string answer1;
public string answer2;
public string answer3;
public string answer4c;
}
public class DataLoader : MonoBehaviour
{
public PickPlace pickplace;
public string URLBase;
public void GetQustion()
{
URLBase = pickplace.url;
StartCoroutine(Run());
}
IEnumerator Run()
{
var req = CreateReturnPlayerDataRequest();
yield return req.SendWebRequest();
var results = HandleReturnPlayerDataRequest(req);
// Izvada konsolē saņemtos datus
Debug.Log("Quesiton: " + results.Result[0].question + " Answer1: " + results.Result[0].answer1 + " Answer2: " + results.Result[0].answer2 + " Answer3: " + results.Result[0].answer3 + " Answer4: " + results.Result[0].answer4c);
}
public UnityWebRequest CreateReturnPlayerDataRequest()
{
var req = UnityWebRequest.Get(URLBase);
return req;
}
public static RootObject HandleReturnPlayerDataRequest(UnityWebRequest req)
{
if (req.isNetworkError)
{
Debug.LogError("Failed to POST /player/register");
return new RootObject();
}
var results = JsonUtility.FromJson<RootObject>("{\"Result\":" + req.downloadHandler.text + "}");
return results;
}
}
My question is:
How can I call out array in, for example my GameManager script and call out separated data, so that I can put for example question text from JSON data into Text object and all 4 answers to buttons?
Currently you have a method to start the request but you never wait until / will know when it is done!
I would simply use an Action<RootObject> as parameter so you can add a callback listener and react to the result when it is invoked.
public class DataLoader : MonoBehaviour
{
public PickPlace pickplace;
public string URLBase;
public void GetQuestions(Action<RootObject> onSuccess)
{
URLBase = pickplace.url;
StartCoroutine(Run(onSuccess));
}
IEnumerator Run(Action<RootObject> onSuccess)
{
var req = CreateReturnPlayerDataRequest();
yield return req.SendWebRequest();
var results = HandleReturnPlayerDataRequest(req);
if(results == null)
{
yield break;
}
Debug.Log("Quesiton: " + results.Result[0].question + " Answer1: " + results.Result[0].answer1 + " Answer2: " + results.Result[0].answer2 + " Answer3: " + results.Result[0].answer3 + " Answer4: " + results.Result[0].answer4c);
// Now invoke the Callback so whoever started the post call gets the results
onSuccess?.Invoke(results);
}
public UnityWebRequest CreateReturnPlayerDataRequest()
{
var req = UnityWebRequest.Get(URLBase);
return req;
}
private RootObject HandleReturnPlayerDataRequest(UnityWebRequest req)
{
if(req.isHttpError || req.isNetworkError)
{
Debug.LogError($"Failed to POST /player/register! Failed with {req.responseCode} - Reason: {req.error}");
onDone?.Invoke(null);
return null;
}
var results = JsonUtility.FromJson<RootObject>("{\"Result\":" + req.downloadHandler.text + "}");
return results;
}
}
So now you can call it from another class like e.g.
// Drag these in via the Inspector
[SerializeField] private DataLoader dataLoader;
[Space]
[SerializeField] private Text questionText;
[Space]
[SerializeField] private Text button1Text;
[SerializeField] private Text button2Text;
[SerializeField] private Text button3Text;
[SerializeField] private Text button3Text;
public void SomeMethod()
{
// Do the post call and react once the results are there either as lambda expression
dataLoader.GetQuestions(results => {
Debug.Log("Successfully received data. Will update GUI", this);
// do something with the results now e.g.
var first = results.Result[0];
questionText.text = first.question;
button1Text.text = first.answer1;
button2Text.text = first.answer2;
button3Text.text = first.answer3;
button4Text.text = first.answer4;
});
// alternatively you can do the same also using a method
dataLoader.GetQuestions(OnPostRequestFinished);
}
private void OnPostRequestFinished(RootObject results)
{
Debug.Log("Successfully received data. Will update GUI", this);
// do something with the results now e.g.
var first = results.Result[0];
questionText.text = first.question;
button1Text.text = first.answer1;
button2Text.text = first.answer2;
button3Text.text = first.answer3;
button4Text.text = first.answer4;
}
I have a WebAPI 2.1 service (ASP.Net MVC 4) that receive and image and related data.
I need to send this image from WPF application, but I get 404 not found error.
Server side
[HttpPost]
[Route("api/StoreImage")]
public string StoreImage(string id, string tr, string image)
{
// Store image on server...
return "OK";
}
Client side
public bool SendData(decimal id, int time, byte[] image)
{
string url = "http://localhost:12345/api/StoreImage";
var wc = new WebClient();
wc.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
var parameters = new NameValueCollection()
{
{ "id", id.ToString() },
{ "tr", time.ToString() },
{ "image", Convert.ToBase64String(image) }
};
var res=wc.UploadValues(url, "POST", parameters);
return true;
}
The url exists, I thing I need to encode to json format, but I don't know how.
Thanks for your time!
The method parameters in your case are received in QueryString form.
I would suggest you turn the parameters list into one single object like this:
public class PhotoUploadRequest
{
public string id;
public string tr;
public string image;
}
Then in you API convert the string to buffer from Base64String like this:
var buffer = Convert.FromBase64String(request.image);
Then cast it to HttpPostedFileBase
HttpPostedFileBase objFile = (HttpPostedFileBase)new MemoryPostedFile(buffer);
Now you have the image file. Do whatever you want.
Full Code here:
[HttpPost]
[Route("api/StoreImage")]
public string StoreImage(PhotoUploadRequest request)
{
var buffer = Convert.FromBase64String(request.image);
HttpPostedFileBase objFile = (HttpPostedFileBase)new MemoryPostedFile(buffer);
//Do whatever you want with filename and its binaray data.
try
{
if (objFile != null && objFile.ContentLength > 0)
{
string path = "Set your desired path and file name";
objFile.SaveAs(path);
//Don't Forget to save path to DB
}
}
catch (Exception ex)
{
//HANDLE EXCEPTION
}
return "OK";
}
Edit:
I forgot to add the Code for MemoryPostedFile class
public class MemoryPostedFile : HttpPostedFileBase
{
private readonly byte[] fileBytes;
public MemoryPostedFile(byte[] fileBytes, string fileName = null)
{
this.fileBytes = fileBytes;
this.FileName = fileName;
this.InputStream = new MemoryStream(fileBytes);
}
public override void SaveAs(string filename)
{
File.WriteAllBytes(filename, fileBytes);
}
public override string ContentType => base.ContentType;
public override int ContentLength => fileBytes.Length;
public override string FileName { get; }
public override Stream InputStream { get; }
}
I need to upload file sending extra paramaters.
I have found the following post in stackoverflow: Webapi ajax formdata upload with extra parameters
It describes how to do this using MultipartFormDataStreamProvider and saving data to fileserver. I do not need to save file to server, but to DB instead.
And I have already working code using MultipartMemoryStreamProvider, but it doesn't use extra parameter.
Can you give me clues how to process extra paramaters in webapi?
For example, if I add file and also test paramater:
data.append("myParameter", "test");
Here is my webapi that processes fileupload without extra paramater:
if (Request.Content.IsMimeMultipartContent())
{
var streamProvider = new MultipartMemoryStreamProvider();
var task = Request.Content.ReadAsMultipartAsync(streamProvider).ContinueWith<IEnumerable<FileModel>>(t =>
{
if (t.IsFaulted || t.IsCanceled)
{
throw new HttpResponseException(HttpStatusCode.InternalServerError);
}
_fleDataService = new FileDataBLL();
FileData fle;
var fleInfo = streamProvider.Contents.Select(i => {
fle = new FileData();
fle.FileName = i.Headers.ContentDisposition.FileName;
var contentTest = i.ReadAsByteArrayAsync();
contentTest.Wait();
if (contentTest.Result != null)
{
fle.FileContent = contentTest.Result;
}
// get extra parameters here ??????
_fleDataService.Save(fle);
return new FileModel(i.Headers.ContentDisposition.FileName, 1024); //todo
});
return fleInfo;
});
return task;
}
Expanding on gooid's answer, I encapsulated the FormData extraction into the provider because I was having issues with it being quoted. This just provided a better implementation in my opinion.
public class MultipartFormDataMemoryStreamProvider : MultipartMemoryStreamProvider
{
private readonly Collection<bool> _isFormData = new Collection<bool>();
private readonly NameValueCollection _formData = new NameValueCollection(StringComparer.OrdinalIgnoreCase);
private readonly Dictionary<string, Stream> _fileStreams = new Dictionary<string, Stream>();
public NameValueCollection FormData
{
get { return _formData; }
}
public Dictionary<string, Stream> FileStreams
{
get { return _fileStreams; }
}
public override Stream GetStream(HttpContent parent, HttpContentHeaders headers)
{
if (parent == null)
{
throw new ArgumentNullException("parent");
}
if (headers == null)
{
throw new ArgumentNullException("headers");
}
var contentDisposition = headers.ContentDisposition;
if (contentDisposition == null)
{
throw new InvalidOperationException("Did not find required 'Content-Disposition' header field in MIME multipart body part.");
}
_isFormData.Add(String.IsNullOrEmpty(contentDisposition.FileName));
return base.GetStream(parent, headers);
}
public override async Task ExecutePostProcessingAsync()
{
for (var index = 0; index < Contents.Count; index++)
{
HttpContent formContent = Contents[index];
if (_isFormData[index])
{
// Field
string formFieldName = UnquoteToken(formContent.Headers.ContentDisposition.Name) ?? string.Empty;
string formFieldValue = await formContent.ReadAsStringAsync();
FormData.Add(formFieldName, formFieldValue);
}
else
{
// File
string fileName = UnquoteToken(formContent.Headers.ContentDisposition.FileName);
Stream stream = await formContent.ReadAsStreamAsync();
FileStreams.Add(fileName, stream);
}
}
}
private static string UnquoteToken(string token)
{
if (string.IsNullOrWhiteSpace(token))
{
return token;
}
if (token.StartsWith("\"", StringComparison.Ordinal) && token.EndsWith("\"", StringComparison.Ordinal) && token.Length > 1)
{
return token.Substring(1, token.Length - 2);
}
return token;
}
}
And here's how I'm using it. Note that I used await since we're on .NET 4.5.
[HttpPost]
public async Task<HttpResponseMessage> Upload()
{
if (!Request.Content.IsMimeMultipartContent())
{
return Request.CreateResponse(HttpStatusCode.UnsupportedMediaType, "Unsupported media type.");
}
// Read the file and form data.
MultipartFormDataMemoryStreamProvider provider = new MultipartFormDataMemoryStreamProvider();
await Request.Content.ReadAsMultipartAsync(provider);
// Extract the fields from the form data.
string description = provider.FormData["description"];
int uploadType;
if (!Int32.TryParse(provider.FormData["uploadType"], out uploadType))
{
return Request.CreateResponse(HttpStatusCode.BadRequest, "Upload Type is invalid.");
}
// Check if files are on the request.
if (!provider.FileStreams.Any())
{
return Request.CreateResponse(HttpStatusCode.BadRequest, "No file uploaded.");
}
IList<string> uploadedFiles = new List<string>();
foreach (KeyValuePair<string, Stream> file in provider.FileStreams)
{
string fileName = file.Key;
Stream stream = file.Value;
// Do something with the uploaded file
UploadManager.Upload(stream, fileName, uploadType, description);
// Keep track of the filename for the response
uploadedFiles.Add(fileName);
}
return Request.CreateResponse(HttpStatusCode.OK, "Successfully Uploaded: " + string.Join(", ", uploadedFiles));
}
You can achieve this in a not-so-very-clean manner by implementing a custom DataStreamProvider that duplicates the logic for parsing FormData from multi-part content from MultipartFormDataStreamProvider.
I'm not quite sure why the decision was made to subclass MultipartFormDataStreamProvider from MultiPartFileStreamProvider without at least extracting the code that identifies and exposes the FormData collection since it is useful for many tasks involving multi-part data outside of simply saving a file to disk.
Anyway, the following provider should help solve your issue. You will still need to ensure that when you iterate the provider content you are ignoring anything that does not have a filename (specifically the statement streamProvider.Contents.Select() else you risk trying to upload the formdata to the DB). Hence the code that asks the provider is a HttpContent IsStream(), this is a bit of a hack but was the simplest was I could think to do it.
Note that it is basically a cut and paste hatchet job from the source of MultipartFormDataStreamProvider - it has not been rigorously tested (inspired by this answer).
public class MultipartFormDataMemoryStreamProvider : MultipartMemoryStreamProvider
{
private readonly Collection<bool> _isFormData = new Collection<bool>();
private readonly NameValueCollection _formData = new NameValueCollection(StringComparer.OrdinalIgnoreCase);
public NameValueCollection FormData
{
get { return _formData; }
}
public override Stream GetStream(HttpContent parent, HttpContentHeaders headers)
{
if (parent == null) throw new ArgumentNullException("parent");
if (headers == null) throw new ArgumentNullException("headers");
var contentDisposition = headers.ContentDisposition;
if (contentDisposition != null)
{
_isFormData.Add(String.IsNullOrEmpty(contentDisposition.FileName));
return base.GetStream(parent, headers);
}
throw new InvalidOperationException("Did not find required 'Content-Disposition' header field in MIME multipart body part.");
}
public override async Task ExecutePostProcessingAsync()
{
for (var index = 0; index < Contents.Count; index++)
{
if (IsStream(index))
continue;
var formContent = Contents[index];
var contentDisposition = formContent.Headers.ContentDisposition;
var formFieldName = UnquoteToken(contentDisposition.Name) ?? string.Empty;
var formFieldValue = await formContent.ReadAsStringAsync();
FormData.Add(formFieldName, formFieldValue);
}
}
private static string UnquoteToken(string token)
{
if (string.IsNullOrWhiteSpace(token))
return token;
if (token.StartsWith("\"", StringComparison.Ordinal) && token.EndsWith("\"", StringComparison.Ordinal) && token.Length > 1)
return token.Substring(1, token.Length - 2);
return token;
}
public bool IsStream(int idx)
{
return !_isFormData[idx];
}
}
It can be used as follows (using TPL syntax to match your question):
[HttpPost]
public Task<string> Post()
{
if (!Request.Content.IsMimeMultipartContent())
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotAcceptable, "Invalid Request!"));
var provider = new MultipartFormDataMemoryStreamProvider();
return Request.Content.ReadAsMultipartAsync(provider).ContinueWith(p =>
{
var result = p.Result;
var myParameter = result.FormData.GetValues("myParameter").FirstOrDefault();
foreach (var stream in result.Contents.Where((content, idx) => result.IsStream(idx)))
{
var file = new FileData(stream.Headers.ContentDisposition.FileName);
var contentTest = stream.ReadAsByteArrayAsync();
// ... and so on, as per your original code.
}
return myParameter;
});
}
I tested it with the following HTML form:
<form action="/api/values" method="post" enctype="multipart/form-data">
<input name="myParameter" type="hidden" value="i dont do anything interesting"/>
<input type="file" name="file1" />
<input type="file" name="file2" />
<input type="submit" value="OK" />
</form>
I really needed the media type and length of the files uploaded so I modified #Mark Seefeldt answer slightly to the following:
public class MultipartFormFile
{
public string Name { get; set; }
public long? Length { get; set; }
public string MediaType { get; set; }
public Stream Stream { get; set; }
}
public class MultipartFormDataMemoryStreamProvider : MultipartMemoryStreamProvider
{
private readonly Collection<bool> _isFormData = new Collection<bool>();
private readonly NameValueCollection _formData = new NameValueCollection(StringComparer.OrdinalIgnoreCase);
private readonly List<MultipartFormFile> _fileStreams = new List<MultipartFormFile>();
public NameValueCollection FormData
{
get { return _formData; }
}
public List<MultipartFormFile> FileStreams
{
get { return _fileStreams; }
}
public override Stream GetStream(HttpContent parent, HttpContentHeaders headers)
{
if (parent == null)
{
throw new ArgumentNullException("parent");
}
if (headers == null)
{
throw new ArgumentNullException("headers");
}
var contentDisposition = headers.ContentDisposition;
if (contentDisposition == null)
{
throw new InvalidOperationException("Did not find required 'Content-Disposition' header field in MIME multipart body part.");
}
_isFormData.Add(String.IsNullOrEmpty(contentDisposition.FileName));
return base.GetStream(parent, headers);
}
public override async Task ExecutePostProcessingAsync()
{
for (var index = 0; index < Contents.Count; index++)
{
HttpContent formContent = Contents[index];
if (_isFormData[index])
{
// Field
string formFieldName = UnquoteToken(formContent.Headers.ContentDisposition.Name) ?? string.Empty;
string formFieldValue = await formContent.ReadAsStringAsync();
FormData.Add(formFieldName, formFieldValue);
}
else
{
// File
var file = new MultipartFormFile
{
Name = UnquoteToken(formContent.Headers.ContentDisposition.FileName),
Length = formContent.Headers.ContentLength,
MediaType = formContent.Headers.ContentType.MediaType,
Stream = await formContent.ReadAsStreamAsync()
};
FileStreams.Add(file);
}
}
}
private static string UnquoteToken(string token)
{
if (string.IsNullOrWhiteSpace(token))
{
return token;
}
if (token.StartsWith("\"", StringComparison.Ordinal) && token.EndsWith("\"", StringComparison.Ordinal) && token.Length > 1)
{
return token.Substring(1, token.Length - 2);
}
return token;
}
}
Ultimately, the following was what worked for me:
string root = HttpContext.Current.Server.MapPath("~/App_Data");
var provider = new MultipartFormDataStreamProvider(root);
var filesReadToProvider = await Request.Content.ReadAsMultipartAsync(provider);
foreach (var file in provider.FileData)
{
var fileName = file.Headers.ContentDisposition.FileName.Replace("\"", string.Empty);
byte[] documentData;
documentData = File.ReadAllBytes(file.LocalFileName);
DAL.Document newRecord = new DAL.Document
{
PathologyRequestId = PathologyRequestId,
FileName = fileName,
DocumentData = documentData,
CreatedById = ApplicationSecurityDirector.CurrentUserGuid,
CreatedDate = DateTime.Now,
UpdatedById = ApplicationSecurityDirector.CurrentUserGuid,
UpdatedDate = DateTime.Now
};
context.Documents.Add(newRecord);
context.SaveChanges();
}
I am a newbie in unity.
i want to send a post request having following json data in unity
**url** = "http://index.php"
**sampple json** = {"id":"100","name":"abc"}
I am using C#
can anyone provide me a solution for this?
I've done for doing this below. Let's go : ==>
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System.Collections.Generic;
public class btnGetData : MonoBehaviour {
void Start()
{
gameObject.GetComponent<Button>().onClick.AddListener(TaskOnClick);
}
IEnumerator WaitForWWW(WWW www)
{
yield return www;
string txt = "";
if (string.IsNullOrEmpty(www.error))
txt = www.text; //text of success
else
txt = www.error; //error
GameObject.Find("Txtdemo").GetComponent<Text>().text = "++++++\n\n" + txt;
}
void TaskOnClick()
{
try
{
GameObject.Find("Txtdemo").GetComponent<Text>().text = "starting..";
string ourPostData = "{\"plan\":\"TESTA02\"";
Dictionary<string,string> headers = new Dictionary<string, string>();
headers.Add("Content-Type", "application/json");
//byte[] b = System.Text.Encoding.UTF8.GetBytes();
byte[] pData = System.Text.Encoding.ASCII.GetBytes(ourPostData.ToCharArray());
///POST by IIS hosting...
WWW api = new WWW("http://192.168.1.120/si_aoi/api/total", pData, headers);
///GET by IIS hosting...
///WWW api = new WWW("http://192.168.1.120/si_aoi/api/total?dynamix={\"plan\":\"TESTA02\"");
StartCoroutine(WaitForWWW(api));
}
catch (UnityException ex) { Debug.Log(ex.Message); }
}
}
Well i've working with something like this:
public class RequestConnectionManager : Manager<RequestConnectionManager>
{
public int maxSubmissionAttempts = 3;
public Coroutine post() {
WWWForm playForm = new WWWForm();
playForm.AddField("id", myJson.id);
playForm.AddField("name", myJson.name);
Post playPost = new Post("http://index.php", playForm, maxSubmissionAttempts, this);
return StartCoroutine(PostWorker(playPost));
}
private IEnumerator PostWorker(Post playPost)
{
yield return null;
yield return playPost.Submit();
Debug.Log(playPost.Response);
if (playPost.Error != null)
{
MessageBoxManager.Instance.Show("Error: " + playPost.Error, "Error", MessageBoxManager.OKCancelOptionLabels, MessageOptions.Ok);
}
else
{
try
{
//do whatever you want in here
//Hashtable response = JsonReader.Deserialize<Hashtable>(playPost.Response);
//Debug.Log("UNITY LOG..." + response);
}
catch (JsonDeserializationException jsExc)
{
Debug.Log(jsExc.Message);
Debug.Log(playPost.Response);
}
catch (Exception exc)
{
Debug.Log(exc.Message);
Debug.Log(playPost.Response);
}
}
}
}
//As for the Manager class...
using UnityEngine;
using System.Collections;
// I wonder what the constraint where TManager : Singleton<TManager> would produce...
public class Manager<TManager> : SingletonW<TManager> where TManager : MonoBehaviour
{
override protected void Awake()
{
base.Awake();
DontDestroyOnLoad(this);
DontDestroyOnLoad(gameObject);
}
}
Hope this helps! =)