post image to asp.net API 2 and angular 2 - asp.net-web-api

i get 415 (Unsupported Media Type) when i try to post image to ASP.Net API 2
The request entity's media type 'multipart/form-data' is not supported for this resource.","exceptionMessage": "No MediaTypeFormatter is available to read an object of type 'Attachment' from content with media type 'multipart/form-data.
my Backend Post method :
[HttpPost]
[Route("api/listing/{listingId}/Attachment/")]
public async Task<dynamic> Post([FromBody] Attachment model)
{
var Attachments = new Attachment
{
ListingId = model.ListingId,
Content = model.Content,
Description = model.Description,
Name = model.Name,
MimeType = model.MimeType,
Size = model.Size,
CreatedOn = DateTime.UtcNow,
UpdatedOn = model.UpdatedOn,
};
return await DataStore.InsertDynamicAsync(Attachments);
}
and my front-end method :
onChangeImage(e: any) {
console.log(this.className + 'onChangeImage.event=' +JSON.stringify(event));
console.log(this.className + 'onChangeImage._listingAttachmentService undefined?: ' + (this._listingAttachmentService === undefined));
const inputElement = this.fileInput.nativeElement;
const fileList = inputElement.files;
const files = [];
console.log('AttachmentsTabComponent: file count = ' + fileList.length);
if (fileList.length > 0) {
for (let i = 0; i < fileList.length; i++) {
// get item
const file = fileList.item(i);
files.push(file);
const model: Attachment = {
listingId: this.listing.id,
mimeType: file.type,
name: file.name,
size: file.size,
updatedOn: file.lastModifiedDate
};
const reader = new FileReader();
reader.readAsDataURL(file);
console.log(this.className + 'onChangeImage.listingAttachmentService (before reader.onload) undefined?: ' + (this._listingAttachmentService === undefined));
reader.onload = (readerEvt: any) => {
const binaryString = readerEvt.target.result;
//base-64 encoded ASCII string
model.content = btoa(binaryString);
console.log(this.className + 'onChangeImage.listingAttachmentService (during reader.onload) undefined?: ' + (this._listingAttachmentService === undefined));
console.log(this.className + 'ListingAttachmentModel.content.length=' + JSON.stringify(model.content.length));
// this._listingAttachmentService.add(model);
};
}
// try to clear the file input
try {
// TODO: fix this
this.fileForm.nativeElement.reset();
inputElement.value = '';
if (inputElement.value) {
inputElement.type = 'text';
inputElement.type = 'file';
}
} catch (e) { }
this._listingAttachmentService.upload(this.listing.id, files)
.subscribe(data => {
this.listing.attachments = data;
});
}
}
and my listingAttachmentService
upload(listingId: number, files: Array<File>) {
this._logger.debug('method upload() entered');
this._logger.debug('upload() listingId=' + listingId);
this._logger.debug('this.fileToUpload.length=' + files.length);
var self = this;
return Observable.create(observer => {
console.log('creating Observable');
let formData: FormData = new FormData(),
xhr: XMLHttpRequest = new XMLHttpRequest();
formData.append('listingId', listingId);
for (let i = 0; i < files.length; i++) {
formData.append('uploads[]', files[i], files[i].name);
}
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
observer.next(JSON.parse(xhr.response));
observer.complete();
} else {
observer.error(xhr.response);
}
}
};
let newbaseUrl = self.baseUrl + listingId + '/attachment/' ;
xhr.open('POST', newbaseUrl, true);
xhr.send(formData);
})
.catch(this.handleError);
}

You should use a custom MediaTypeFormatter. More information here: http://www.asp.net/web-api/overview/formats-and-model-binding/media-formatters and a sample here http://blog.marcinbudny.com/2014/02/sending-binary-data-along-with-rest-api.html#.V5MDDzV7qYg
public class CustomFormatter : MediaTypeFormatter
{
public CustomFormatter()
{
SupportedMediaTypes.Add(new MediaTypeHeaderValue("multipart/form-data"));
}
public override bool CanReadType(Type type)
{
return type == typeof(Attachment);
}
public override bool CanWriteType(Type type)
{
return false;
}
public async override Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger)
{
var provider = await content.ReadAsMultipartAsync();
var modelContent = provider.Contents
.FirstOrDefault(c => c.Headers.ContentType.MediaType == "application/json"); // Can also use ContentDisposition.Name.Normalize == "attachment"
var attachment = await modelContent.ReadAsAsync<Attachment>();
var fileContents = provider.Contents
.Where(c => c.Headers.ContentType.MediaType == "image/jpeg").FirstOrDefault(); // can also use ContentDisposition.Name.Normalize() == "image"
attachment.Content = await fileContents.ReadAsByteArrayAsync();
return attachment;
}
}
Register the custom media formatter:
private void ConfigureWebApi(HttpConfiguration config)
{
//other code here
config.Formatters.Add(new CustomFormatter());
}
A post will like below
POST http://localhost/api/FileUpload HTTP/1.1
Content-Type: multipart/form-data; boundary=-------------------------acebdf13572468
User-Agent: Fiddler
Content-Length: 88778
---------------------------acebdf13572468
Content-Type: application/json; charset=utf-8
Content-Disposition: form-data; name=attachment
{"ListingId":"testl"}
---------------------------acebdf13572468
Content-Disposition: form-data; name=image; filename=image.jpg
Content-Type: image/jpeg
Image content
---------------------------acebdf13572468--
Hope this helps.

Related

Error passing multiple input files, Design Automation Revit dot net core

I had asked my last question regarding this. I have one rfa file and a bigger JSon file as input. When I debug, it looks perfectly passing all values until last line:
WorkItemStatus workItemStatus = await _designAutomation.CreateWorkItemAsync(workItemSpec);
Looks like workItemSpec has some problem. Please have a look at these code fractions and please let me know what is wrong here.
code fraction from ForgeDesignAutomation.js as below:
{
var inputFileField = document.getElementById('inputFile');
if (inputFileField.files.length === 0) { alert('Please select an input file'); return; }
if ($('#activity').val() === null) { alert('Please select an activity'); return };
var file = inputFileField.files[0];
var inputFileField2 = document.getElementById('inputJsonFile');
if (inputFileField2.files.length === 0) { alert('Please select an input file'); return; }
var file2 = inputFileField2.files[0];
let activityId = $('#activity').val();
if (activityId == null)
{
alert('Please select an activity'); return
};
if (activityId.toLowerCase() === "_da4ractivity+dev")
{
startConnection(function () {
var formData = new FormData();
formData.append('inputFile', file);
formData.append('inputJsonFile', file2);
formData.append('data', JSON.stringify({
activityName: $('#activity').val(),
browerConnectionId: connectionId
}));
writeLog('Uploading input file...');
$.ajax({
url: 'api/forge/designautomation/workitems',
data: formData,
processData: false,
contentType: false,
type: 'POST',
success: function (res)
{
writeLog('Workitem started: ' + res.workItemId);
}
});
});
}
}```
code fraction from "CreateActivity" in DesignAutomationController.cs
``` Parameters = new Dictionary<string, Parameter>()
{
{ "inputFile", new Parameter() { Description = "input file", LocalName = "$(inputFile)", Ondemand = false, Required = true, Verb = Verb.Get, Zip = false } },
{ "inputJsonFile", new Parameter() { Description = "input Json file", LocalName = "$(inputJsonFile)", Ondemand = false, Required = true, Verb = Verb.Get, Zip = false } },
{ "outputFile", new Parameter() { Description = "output file", LocalName = "outputFile." + engineAttributes.extension, Ondemand = false, Required = true, Verb = Verb.Put, Zip = false } }
}```
code fraction from "StartWorkitem" in DesignAutomationController.cs
``` [HttpPost]
[Route("api/forge/designautomation/workitems")]
public async Task<IActionResult> StartWorkitem([FromForm]StartWorkitemInput input)
{
// basic input validation
JObject workItemData = JObject.Parse(input.data);
string activityName = string.Format("{0}.{1}", NickName, workItemData["activityName"].Value<string>());
string browerConnectionId = workItemData["browerConnectionId"].Value<string>();
// save the file on the server
var fileSavePath0 = Path.Combine(_env.ContentRootPath, Path.GetFileName(input.inputFile.FileName));
using (var stream0 = new FileStream(fileSavePath0, FileMode.Create)) await input.inputFile.CopyToAsync(stream0);
var fileSavePath1 = Path.Combine(_env.ContentRootPath, Path.GetFileName(input.inputJsonFile.FileName));
using (var stream1 = new FileStream(fileSavePath1, FileMode.Create)) await input.inputJsonFile.CopyToAsync(stream1);
//---------------------------------------------------------------------------------------------------------------------
// OAuth token
dynamic oauth = await OAuthController.GetInternalAsync();
// upload file to OSS Bucket
// 1. ensure bucket existis
string bucketKey = NickName.ToLower() + "-designautomation";
BucketsApi buckets = new BucketsApi();
buckets.Configuration.AccessToken = oauth.access_token;
try
{
PostBucketsPayload bucketPayload = new PostBucketsPayload(bucketKey, null, PostBucketsPayload.PolicyKeyEnum.Transient);
await buckets.CreateBucketAsync(bucketPayload, "US");
}
catch { };
// in case bucket already exists
// 2. upload inputFile
string inputFileNameOSS0 = string.Format("{0}_input_{1}", DateTime.Now.ToString("yyyyMMddhhmmss"), Path.GetFileName(input.inputFile.FileName)); // avoid overriding
string inputFileNameOSS1 = string.Format("{0}_inputJson_{1}", DateTime.Now.ToString("yyyyMMddhhmmss"), Path.GetFileName(input.inputJsonFile.FileName)); // avoid overriding
//string inputFileNameOSS = Path.GetFileName(input.inputFile.FileName); // avoid overriding
ObjectsApi objects = new ObjectsApi();
objects.Configuration.AccessToken = oauth.access_token;
using (StreamReader streamReader = new StreamReader(fileSavePath0))
await objects.UploadObjectAsync(bucketKey, inputFileNameOSS0, (int)streamReader.BaseStream.Length, streamReader.BaseStream, "application/octet-stream");
System.IO.File.Delete(fileSavePath0);// delete server copy
// prepare workitem arguments
// 1. input file
XrefTreeArgument inputFileArgument = new XrefTreeArgument()
{
Url = string.Format("https://developer.api.autodesk.com/oss/v2/buckets/{0}/objects/{1}", bucketKey, inputFileNameOSS0),
Headers = new Dictionary<string, string>()
{
{ "Authorization", "Bearer " + oauth.access_token }
}
};
using (StreamReader streamReader1 = new StreamReader(fileSavePath1))
await objects.UploadObjectAsync(bucketKey, inputFileNameOSS1, (int)streamReader1.BaseStream.Length, streamReader1.BaseStream, "application/octet-stream");
System.IO.File.Delete(fileSavePath1);// delete server copy
// 1. input Json file
XrefTreeArgument inputJsonArgument = new XrefTreeArgument()
{
Url = string.Format("https://developer.api.autodesk.com/oss/v2/buckets/{0}/objects/{1}", bucketKey, inputFileNameOSS1),
Headers = new Dictionary<string, string>()
{
{ "Authorization", "Bearer " + oauth.access_token }
}
};
// 3. output file
string outputFileNameOSS = string.Format("{0}_output_{1}", DateTime.Now.ToString("yyyyMMddhhmmss"), Path.GetFileName(input.inputFile.FileName)); // avoid overriding
XrefTreeArgument outputFileArgument = new XrefTreeArgument()
{
Url = string.Format("https://developer.api.autodesk.com/oss/v2/buckets/{0}/objects/{1}", bucketKey, outputFileNameOSS),
Verb = Verb.Put,
Headers = new Dictionary<string, string>()
{
{"Authorization", "Bearer " + oauth.access_token }
}
};
// prepare & submit workitem
string callbackUrl = string.Format("{0}/api/forge/callback/designautomation?id={1}&outputFileName={2}", OAuthController.GetAppSetting("FORGE_WEBHOOK_URL"), browerConnectionId, outputFileNameOSS);
WorkItem workItemSpec = new WorkItem()
{
ActivityId = activityName,
Arguments = new Dictionary<string, IArgument>()
{
{ "inputFile", inputFileArgument },
{ "inputJsonFile", inputJsonArgument },
{ "outputFile", outputFileArgument },
{ "onComplete", new XrefTreeArgument { Verb = Verb.Post, Url = callbackUrl } }
}
};
WorkItemStatus workItemStatus = await _designAutomation.CreateWorkItemAsync(workItemSpec);
return Ok(new { WorkItemId = workItemStatus.Id });
}```
```/// <summary>
/// Input for StartWorkitem
/// </summary>
public class StartWorkitemInput[![enter image description here][1]][1]
{
public IFormFile inputFile { get; set; }
public IFormFile inputJsonFile { get; set; }
public string data { get; set; }
} ```
[![enter image description here][1]][1]
[1]: https://i.stack.imgur.com/GktUC.png
I noticed your activity defines the "localName" of "inputFile"/"inputJsonFile" to be "$(inputFile)"/"$(inputJsonFile)"
Parameters = new Dictionary<string, Parameter>()
{
{ "inputFile", new Parameter() { Description = "input file", LocalName = "$(inputFile)", Ondemand = false, Required = true, Verb = Verb.Get, Zip = false } },
{ "inputJsonFile", new Parameter() { Description = "input Json file", LocalName = "$(inputJsonFile)", Ondemand = false, Required = true, Verb = Verb.Get, Zip = false } }
}
This could cause some issue when resolving the naming of inputs during the job process. I would suggest you provide a concrete filename as WorkItem argument's localname and try again. For example:
XrefTreeArgument inputJsonArgument = new XrefTreeArgument()
{
Url = string.Format("https://developer.api.autodesk.com/oss/v2/buckets/{0}/objects/{1}", bucketKey, inputFileNameOSS1),
Headers = new Dictionary<string, string>()
{
{ "Authorization", "Bearer " + oauth.access_token }
},
// Note: if your appbunldes(addin) uses this json, this is the name your addin should know
LocalName = "inputJson.json"
};

Chromecast Reciever App Error : '[goog.net.WebSocket] The WebSocket disconnected unexpectedly: undefined '

While creating a receiver application in chromecast we are getting a problem as :
[goog.net.WebSocket] The WebSocket disconnected unexpectedly: undefined
cast_receiver_framework.js:507 WebSocket connection to 'ws://localhost:8008/v2/ipc' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED
Our receiver has simple code as in example provided by CAF receiver in chromecast documentation:
const context = cast.framework.CastReceiverContext.getInstance();
const playerManager = context.getPlayerManager();
const playbackConfig = new cast.framework.PlaybackConfig();
// Customize the license url for playback
playbackConfig.licenseUrl = 'https://wv-keyos.licensekeyserver.com/';
playbackConfig.protectionSystem = cast.framework.ContentProtection.WIDEVINE;
playbackConfig.licenseRequestHandler = requestInfo => {
requestInfo.withCredentials = true;
requestInfo.headers = {
'customdata': '<customdata>'
};
};
context.getPlayerManager().setMediaPlaybackInfoHandler((loadRequest, playbackConfig) => {
if (loadRequest.media.customData && loadRequest.media.customData.licenseUrl) {
playbackConfig.licenseUrl = loadRequest.media.customData.licenseUrl;
}
return playbackConfig;
});
function makeRequest (method, url) {
return new Promise(function (resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open(method, url);
xhr.onload = function () {
if (this.status >= 200 && this.status < 300) {
resolve(JSON.parse(xhr.response));
} else {
reject({
status: this.status,
statusText: xhr.statusText
});
}
};
xhr.onerror = function () {
reject({
status: this.status,
statusText: xhr.statusText
});
};
xhr.send();
});
}
playerManager.setMessageInterceptor(
cast.framework.messages.MessageType.LOAD,
request => {
castDebugLogger.info('MyAPP.LOG', 'Intercepting LOAD request');
if (request.media && request.media.entity) {
request.media.contentId = request.media.entity;
}
return new Promise((resolve, reject) => {
if(request.media.contentType == 'video/mp4') {
return resolve(request);
}
// Fetch content repository by requested contentId
makeRequest('GET', 'https://tse-summit.firebaseio.com/content.json?orderBy=%22$key%22&equalTo=%22'+ request.media.contentId + '%22')
.then(function (data) {
var item = data[request.media.contentId];
if(!item) {
// Content could not be found in repository
castDebugLogger.error('MyAPP.LOG', 'Content not found');
reject();
} else {
// Adjusting request to make requested content playable
request.media.contentId = item.stream.hls;
request.media.contentType = 'application/x-mpegurl';
castDebugLogger.warn('MyAPP.LOG', 'Playable URL:', request.media.contentId);
// Add metadata
var metadata = new cast.framework.messages.MovieMediaMetadata();
metadata.metadataType = cast.framework.messages.MetadataType.MOVIE;
metadata.title = item.title;
metadata.subtitle = item.author;
request.media.metadata = metadata;
resolve(request);
}
});
});
});
/** Debug Logger **/
const castDebugLogger = cast.debug.CastDebugLogger.getInstance();
// Enable debug logger and show a warning on receiver
// NOTE: make sure it is disabled on production
castDebugLogger.setEnabled(false);
playerManager.addEventListener(
cast.framework.events.category.CORE,
event => {
castDebugLogger.info('ANALYTICS', 'CORE EVENT:', event);
});
// Set verbosity level for custom tags
castDebugLogger.loggerLevelByTags = {
'MyAPP.LOG': cast.framework.LoggerLevel.WARNING,
'ANALYTICS': cast.framework.LoggerLevel.INFO,
};
/** Optimizing for smart displays **/
const playerData = new cast.framework.ui.PlayerData();
const playerDataBinder = new cast.framework.ui.PlayerDataBinder(playerData);
const touchControls = cast.framework.ui.Controls.getInstance();
let browseItems = getBrwoseItems();
function getBrwoseItems() {
let data = '"video": { \
<Encrypted Video>
}, \
"title": "Big Buck Bunny" \
}';
let browseItems = [];
for (let key in data) {
let item = new cast.framework.ui.BrowseItem();
item.entity = key;
item.title = data[key].title;
item.subtitle = data[key].description;
item.image = new cast.framework.messages.Image(data[key].poster);
item.imageType = cast.framework.ui.BrowseImageType.MOVIE;
browseItems.push(item);
}
return browseItems;
}
let browseContent = new cast.framework.ui.BrowseContent();
browseContent.title = 'Up Next';
browseContent.items = browseItems;
browseContent.targetAspectRatio =
cast.framework.ui.BrowseImageAspectRatio.LANDSCAPE_16_TO_9;
playerDataBinder.addEventListener(
cast.framework.ui.PlayerDataEventType.MEDIA_CHANGED,
(e) => {
if (!e.value) return;
// Clear default buttons and re-assign
touchControls.clearDefaultSlotAssignments();
touchControls.assignButton(
cast.framework.ui.ControlsSlot.SLOT_1,
cast.framework.ui.ControlsButton.SEEK_BACKWARD_30
);
// Media browse
touchControls.setBrowseContent(browseContent);
});
context.start({playbackConfig: playbackConfig});
This code takes the input from sender but even if sender has application ID it shows the same message.

Angular2 to Asp.net Core Webapi IFormFile is null

I am using angular2 with asp.net core webapi. Using the following code to send file information. IFormFile is always null. I have used same name in post input and in api method parameter, still no luck. Please help me.
FormData
this.formData.append("file", f,f.name);
Component method
public UploadFiles() {
console.log("Form Data:" + this.formData);
let saved: boolean = false;
this.claimsService
.UploadFiles(this.formData)
.subscribe(data => {
saved = data;
}, error => {
console.log(error)
swal(error);
})
}
Service Method
UploadFiles(data: FormData): Observable<boolean> {
return this.ExecuteFilePost("Upload/Upload", data);
}
Base Service Method:
public ExecuteFilePost(action: string, data: FormData) {
let _body = data;
let headers = new Headers({ 'Content-Type': undefined});
let url = this._baseUrl + action;
let requestoptions: RequestOptions = new RequestOptions({
headers: headers,
});
console.log('req url:' + url);
return this.http.post(url,_body,requestoptions)
.share()
.map((res: Response) => {
if (res.status < 200 || res.status >= 300) {
throw new Error('This request has failed ' + res.status);
}
else {
return res.json();
}
});
}
WebApi Method
[HttpPost]
[ActionName("Upload")]
public async Task Upload(IFormFile file)
{
var uploads = Path.Combine(_environment.WebRootPath, "uploads");
// foreach (var file in files)
// {
if (file.Length > 0)
{
using (var fileStream = new FileStream(Path.Combine(uploads, file.FileName), FileMode.Create))
{
await file.CopyToAsync(fileStream);
}
}
// }
}
Chrome request screens
enter image description here
I know the post is old, but maybe for others. You can do things like this:
HTML:
<input #fileInput type="file" multiple />
<button (click)="addFile()">Add</button>
Component:
#ViewChild("fileInput") fileInput;
addFile(): void {
let fi = this.fileInput.nativeElement;
if (fi.files) {
let fileToUpload = fi.files;
this.settingsService
.upload(fileToUpload)
.subscribe(res => {
console.log(res);
});
}
}
Service:
upload(files: any) {
let formData = new FormData();
for (let i = 0; i < files.length; i++) {
formData.append("files", files[i]);
}
return this.http
.post(fileUploadApi, formData)
.map(response => this.extractData(response as Response))
.catch(error => this.httpErrorHandlerService.responseError(error));
}
Web API
[HttpPost]
[Route("Upload")]
public IActionResult UploadFiless([FromForm] IFormFileCollection files)
{
try
{
return this.Ok();
}
catch (Exception)
{
return this.BadRequest();
}
}

MVC Ajax function call twice

I have a problem with an ajax function. I want to send param to method on controller and this ajax function call method twice.
ajax:
$(document).ready(function () {
$(document).on('click', '.exp', function (e) {
var st_date = $(this).parent().find('.start').val();
var ed_date = $(this).parent().find('.end').val();
$.ajax({
url: '/Reports/Report_CLeav/',
data: {
start_date:st_date,
end_date:ed_date
}
}).success(function (data) {
})
});
})
$(".exp").click(function() {
var st_date = $(this).parent().find('.start').val();
var ed_date = $(this).parent().find('.end').val();
$.ajax({
url: '/Reports/Report_CLeav/',
data: {
start_date:st_date,
end_date:ed_date
}
}).success(function (data) {
})
});
?
<th>
Start date: #Html.TextBox("start_date", null, new { #class = "dateClass start", id = "StartDate" })
End date: #Html.TextBox("end_date", null, new { #class = "dateClass end", id = "EndDate", #data_toggle = "popover", #data_content = "End date should be greater than Start date. ", #title = "Attention" })
#Html.ActionLink("Export Report", "Report_CLeav", "Reports", new { #class = "IndexButton exp", #style = "text-decoration: none;color:white" })
</th>
"Controller"
public class ReportsController : Controller
{
// GET: Export
public ActionResult Index()
{
return View();
}
public void Report_CLeav(DateTime ?start_date, DateTime ? end_date)
{
string path = HttpContext.Server.MapPath("~/App_Data/reports/Report_LeavingCompanyHCT.xlsx");
Models.Report.Report_CompLeav reportcompleav = new Models.Report.Report_CompLeav();
var fileinfo = new FileInfo(path);
using (ExcelPackage package = new ExcelPackage(fileinfo))
{
var currentWorksheet = package.Workbook.Worksheets["HC"];
using (var excelToExport = new ExcelPackage())
{
excelToExport.Workbook.Worksheets.Add(currentWorksheet.Name, currentWorksheet);
var workBook = excelToExport.Workbook.Worksheets["HC"];
try
{
workBook = reportcompleav.exportAllEmployeeDataRRecords(workBook,start_date,end_date);
}
catch (Exception e)
{
ViewBag.IsError = true;
}
excelToExport.Save();
Stream stream = excelToExport.Stream;
var memoryStream = stream as MemoryStream;
Response.Clear();
Response.ContentType = "application/vnd.openxmlformats";
Response.AddHeader("Content-Disposition",
"attachment; filename=" + fileinfo.Name);
Response.BinaryWrite(memoryStream.ToArray());
}
}
}
}
}

Control flow with XmlHttpRequest?

XmlHttpRequest works through callbacks. So how can I return a value? I tried to set a global variable, but that doesn't seem to be working.
var response = null; // contains the most recent XmlHttpRequest response
// loads the info for this username on the page
function loadUsernameInfo(username) {
getUserInfo(username);
var profile = response;
if (profile) {
// do stuff
}
else {
indicateInvalidUsername(username);
}
}
getUserInfo() can't return a result, because of the callback:
function getUserInfo(username) {
var request = createRequest();
request.onreadystatechange = userObjFromJSON;
var twitterURL = "http://twitter.com/users/show/" + escape(username) + ".json";
var url = "url.php?url=" + twitterURL;
request.open("GET", url, true);
request.send(null);
}
The callback:
function userObjFromJSON() {
if (this.readyState == 4) {
alert(this.responseText);
response = this.responseText;
}
}
How can I get the response back to loadUsernameInfo()?
You can do synchronous requests, though it is not recommended - the A is for Asynchronous... But the general idea to implement this correctly would be:
var response = null; // contains the most recent XmlHttpRequest response
// loads the info for this username on the page
function loadUsernameInfo(username) {
getUserInfo(username, onLoadUsernameComplete);
}
function getUserInfo(username, oncomplete) {
var request = createRequest();
request.__username = username;
request.onreadystatechange = oncomplete;
var twitterURL = "http://twitter.com/users/show/" + escape(username) + ".json";
var url = "url.php?url=" + twitterURL;
request.open("GET", url, true);
request.send(null);
}
function onLoadUsernameComplete(req) {
if (req.readyState == 4) {
// only if "OK"
if (req.status == 200) {
var profile = req.responseXML;
if (profile) {
// do stuff
}
else {
indicateInvalidUsername(req.__username);
}
}
}
}

Resources