InvalidOperationException when sending get request in browser tab despite working in ajax - angularjs

I have an ajax request done with angular, its very basic, here is the code:
$http.get(url,data).success(function(data){
//Do Stuff with data
});
This works fine and the data is all good.
But when i inspect the request on the network tab in Chrome, and i right click on the request and click Open in new tab I get the following error:
<ExceptionMessage>
The 'ObjectContent`1' type failed to serialize the response body for content type 'application/xml; charset=utf-8'.
</ExceptionMessage>
<ExceptionType>System.InvalidOperationException</ExceptionType>
Here is the api controller code:
[AcceptVerbs("GET")]
public object SearchRetailers(long userId, string term)
{
List<Tuple<int,string>> res = userService.SearchRetailers(userId, term);
return res.Take(20).Select(x => new
{
label = x.Item2 + " - " + x.Item1,
value = x.Item1
});
}
The code works fine and does not throw any exceptions.
i think this might have something to do with the request headers, i just want it to work when opened in the browser regularly.
Its important to note I am using Umbraco so the apicontroller inherits UmbracoApiController class.
Also, i don't see any apiwebconfig file anywhere so i cant implement other solutions i found, and my global asax also looks significantly different than in other questions i encountered, here is how it looks:
<%# Application Inherits="Umbraco.Web.UmbracoApplication" Language="C#" %>
<script RunAt="server">
protected void Application_PostAuthorizeRequest()
{
if (IsWebApiRequest())
{
HttpContext.Current.SetSessionStateBehavior(SessionStateBehavior.Required);
}
}
private bool IsWebApiRequest()
{
return HttpContext.Current.Request.AppRelativeCurrentExecutionFilePath.Contains("/api/");
}
</script>

Related

CefSharp: Injecting custom CSS File using a custom scheme

I'm using CefSharp (47) to render a webpage from a host that I have no control over, and I want to make some additional CSS tweaks to those provided by the host.
Reading up on various topics across GitHub (https://github.com/cefsharp/CefSharp/blob/cefsharp/47/CefSharp.Example/CefSharpSchemeHandlerFactory.cs), and here (CefSharp custom SchemeHandler), I wrote a custom scheme handler accordingly:
public class CustomSchemeHandlerFactory : ISchemeHandlerFactory
{
public const string SchemeName = "custom";
public IResourceHandler Create(IBrowser browser, IFrame frame, string schemeName, IRequest request)
{
Console.WriteLine(request.Url);
if (schemeName.ToLower() == SchemeName.ToLower())
{
// Do some stuff
}
return null;
}
}
I attempt to bind it in my application in the following manner:
CefSettings settings = new CefSettings();
settings.CachePath = browserCachePath;
settings.RegisterScheme(new CefCustomScheme()
{
SchemeName = CustomSchemeHandlerFactory.SchemeName,
SchemeHandlerFactory = new CustomSchemeHandlerFactory()
});
Cef.Initialize(settings);
The application then browses to the appropriate website, and uses the 'LoadingStateChanged' event to then fire off some JavaScript to inject the CSS file I want to load:
string linkText = "<link rel=\u0022stylesheet\u0022 type=\u0022text/css\u0022 href=\u0022custom://custom.css\u0022>";
var jsFunctionText = string.Format("(function() {{ $('head').append('{0}'); return true;}}) ();", linkText);
var injectionTask = await _myBrowser.GetMainFrame().EvaluateScriptAsync(jsFunctionText, null);
...which succeeds.
But my custom resource handler 'Create' event is never fired.
I can only presume that the handler isn't being registered properly, so I'd appreciate any advice/help in getting this working properly!
Thanks!

Angular : show image from REST Service

After reseaches and tests, I still can't show an image form ReST API on my Angular App. I have images available on my ReST web service, why do I use a ReST service? Because in order to access you need to be authenticated (I use oAuth 2 protocol). When I use POSTMan (ReST client very usefull) everything works great, the image is displayed without doing nothing. But when I try to display it with Angular after a $http it doesn't work.
Here are the headers received form the service :
Content-Length → 51756
Content-Type → image/jpeg; charset=binary
Server → Apache/2.4.9 (Win64) PHP/5.5.12
X-Powered-By → PHP/5.5.12
Here is my Angular code :
var data64 = $base64.encode(unescape(encodeURIComponent(data)));
scope.src = 'data:image/jpeg;charset=binary;base64,' + data64;
and my HTML :
<img ng-src="{{src}}" border="0" />
For information I use angular-base64 (https://github.com/ninjatronic/angular-base64) for the encodage. Without "unescape" and "encodeURIComponent" I have an error, I've tried to remove white spaces but it still doesn't work.
Thank you :)
Seems that this will not work since you tell the browser that the image data is base64 encoded, but you also transformed it with unescape and encodeURIComponent.
Why don't you fetch your image data into a binary data structure (requires a modern browser), instead of into a string:
$http.get(req, {responseType: "arraybuffer"}).
success(function(data) {
$scope.src = 'data:image/jpeg;base64,' + _arrayBufferToBase64(data);
});
_arrayBufferToBase64 is defined here.
A different approach would be to install a request interceptor, recognize the image url and add the oauth headers for this case.
I tryed this way in angular 8+ and works fine:
imageToShow: any;
createImageFromBlob(image: Blob) {
let reader = new FileReader();
reader.addEventListener("load", () => {
this.imageToShow = reader.result;
}, false);
if (image) {
reader.readAsDataURL(image);
}
}
and also call it like this:
getImageFromService() {
this.api.getImage(key).subscribe(data => {
this.createImageFromBlob(data);
}, error => {
console.log(error);
});
}

SignalR doesn't push message to client

I am implementing functionality to notify the user of long running job completions using SignalR in an AngularJS application.I have created groups of user based on their name,so for each user a group of his name and different connectionids which he has opened up will be created and he would be notified by his group. I want to notify the user on two pages i.e. landing Page and Job Run Page as even if the user is on landing page and job run completes he should be notified of it.
For the same reason i am creating group by his name on both the pages,so that if he is on any page he would be nofied through the group.
On landing page controller js file i have written code to add the user in group as follow...
$rootScope.signalRHub = $.connection.signalRHub;
$rootScope.hubStart = null;
$rootScope.startHub = function () {
if ($rootScope.hubStart == null)
{
$rootScope.hubStart = $.connection.hub.start();
}
return $rootScope.hubStart;
}
$scope.$on('$locationChangeStart', function (event) {
if ($rootScope.userName != "") {
$rootScope.signalRHub.server.leaveGroup($rootScope.userName);
}
});
// Start the connection
$rootScope.startHub().done(function () {
$rootScope.signalRHub.server.joinGroup($rootScope.userName);
});
on Job Run controller js file i have written following code....
$rootScope.signalRHub.client.showNotification = function (message) {
notify('Your notification message');//notify is the angular js directive injected in this controller which runs fine
};
$scope.$on('$locationChangeStart', function (event) {
$rootScope.signalRHub.server.leaveGroup($rootScope.studyid);
});
// Start the connection
$rootScope.startHub().done(function () {
$rootScope.signalRHub.server.joinGroup($rootScope.userName
});
My Hub File.....
[EnableCors(origins: "*", headers: "*", methods: "*")]
public class SignalRHub : Hub
{
public Task JoinGroup(string groupName)
{
return Groups.Add(Context.ConnectionId, groupName);
}
public Task LeaveGroup(string groupName)
{
return Groups.Remove(Context.ConnectionId, groupName);
}
public void ShowNotification(string jobRunDetailId, string userName)
{
if (!string.IsNullOrEmpty(userName))
{
var context = GlobalHost.ConnectionManager.GetHubContext<SignalRHub>();
context.Clients.Group(userName).showNotification(jobRunDetailId);
}
}
}
The issue is when i run the application the group add functionality for both pages works fine.but when i call "showNotification" from Hub it doesn't show any message.
But strange thing is if i comment the "$rootScope.startHub().done...." function on landing page then the jobrun page notify functionality works fine.I am not sure if writing "$rootScope.startHub().done()..." on two places is creating this problem.please help.
You need to wire up all callbacks before calling start. If you turn client side logging on, it'll tell you what hubs you are subscribed to.
Aside:
[EnableCors] is a webapi specific attribute that does not work in SignalR.

AngularJS ajax resulting in two calls for html & json

So I turned on network capture in my web browser to have a look at my ajax calls coming out of AngularJS. For every call made, there seems to be two results:
URL|Protocol|Method|Result|Type|Received|Taken
/p/jobs/03512dc8-6f25-49ea-bdff-0028ac2023cb|HTTP|GET|301|text/html|408 B|< 1 ms
/p/jobs/03512dc8-6f25-49ea-bdff-0028ac2023cb|HTTP|GET|200|application/json|0.79 KB|15 ms
It looks like it's attempting to request HTML first, getting a 301 and then requesting the JSON. How can I eliminate the request for HTML? I'm using $resource to do this but I'd also like to see an example for $http.
Also, the receiving framework is NancyFX for .NET. Perhaps there's a header I need to specify to make sure it always returns JSON? I've tried the "Accept" header but it seems to make no difference. It's as if Nancy is always trying to return a View first before switching to JSON.
Javascript code (translated slightly from TypeScript):
$resource(jobUrl, {}, { get: {method: "GET", isArray: false }});
Nancy code:
public class JobService : NancyModule
{
public static readonly string Prefix = "/p/jobs";
WebLogger logger;
public JobService(WebLogger logger)
: base(Prefix)
{
this.logger = logger;
Get[""] = _ => GetJobs();
Get["/{id}"] = _ => GetJob(_.id);
Get["/{id}/nodes"] = _ => GetNodes(_.id);
Get["/{id}/faults"] = _ => GetFaults(_.id);
}
Job GetJob(string id)
{
lock (logger)
{
if (logger.JobGuid != id)
{
Context.Response.StatusCode = HttpStatusCode.NotFound;
return null;
}
return MakeJob();
}
}
Some part of your code will be helpful, but lets try - you have put character / at the end of $resource definition. Angular has asked server for content for directory, server response with header 301 - redirect to file as Angular expects some data response than directory listing.

415 (Unsupported Media Type) in $http.post method

I'm quite new to REST and AngularJS, but after several hours of googling I couldn't find any answer to my question:
I'm trying to do a POST request from my angularjs frontend to my backend implemented in java (using JPA).
When I'm trying to create a json-object and to do a POST I always get the 415 (Unsupported Media Type) error.
(Actually I don't even get "into" the scope of the service (i.E. "IN SERVICE" doesn't get printed to the console)..
If I add postData.toJSON(), it actually gets "POSTed", but arrives null ...
how do I have to format my 'postData' in Order to succesfully get POSTed?
(I also tried to write the Date-properties without ' " ' - no luck...)
Thank you for your help!
FrontEnd:
app.controller('WorkController', function($scope, $http) {
$scope.saveWork = function () {
var postData = {
"status" : "OPEN",
"startDate": "1338364250000",
"endDate": "1336364253400",
"WorkText" : "Test"
};
$http.post("http://localhost:8080/service/v1/saveWork", postData)
.success(function(data, status, headers, config){
console.log("IN SAVE WORK - SUCCESS");
console.log(status);
})
.error(function(){
console.log("ERROR IN SAVE WORK!");
})
}
});
Service:
#POST
#Consumes(MediaType.APPLICATION_JSON)
public Response save(WorkDto wo){
System.out.println("IN SERVICE");
if(ass == null){
System.out.println("Could nor persist work- null");
return Response.noContent().build();
} else{
Work workDao = WorkTransformator.transform(wo);
workDao.persist();
return Response.ok().build();
}
}
Instead of building and sending a parsed JSON object, create a javascript object and send that in your post body. You can reuse your postData object, but try removing the "" surrounding properties names.
Try this:
var postData = {
status : "OPEN",
startDate: "1338364250000",
endDate: "1336364253400",
workText : "Test"
};
UPDATE
Looks like the above doesn't work by itself. I thought that the Content-Type would be infered.
Can you try to do the post request this way :
$http({
method: 'POST',
url: 'http://localhost:8080/service/v1/saveWork',
data: postData,
headers: {
'Content-Type': 'application/json'
}}); // complete with your success and error handlers...
// the purpose is to try to do the post request explicitly
// declaring the Content-Type you want to send.
UPDATE 2
If this didn't work, compose a post request using Fiddler, and check what's the response.
Here's some pointers:
Download Fiddler2 if you dont already have it
Compose a request like in the screenshot below
You can then check on the pane on the left for what was the server response code. Double click that line (Ignore the error code on the screenshot...you should be getting a 415)
After double-clicking the response line, you can check and browse for more details on the right pane:
If you can successfuly post with a «manufactured» JSON object then the problem resides on your Angular code. If not, it's certainly something wrong with your Rest Service configuration.
You can also inspect the details of your POSTS made with the Angular app in Fiddler2. That should give you a good insight of what's going on.
If you're into it, you can then update your question with some screenshots of your Angular app requests. That will certainly help us to help you :)
I finally managed to find the cause of my error!
In my Rest-Service, I directly expected my java-class as parameter. (I thought this would be parsed/deserialized automatically). Quite naive I think... :)
In order to get it working I had to:
-Expect a String as Parameter in my #POST service
-Deserialize it (using GSON)
Here is the (now working) service:
#POST
#Consumes(MediaType.APPLICATION_JSON)
public Response save(String wo){
if(wo == null){
System.out.println("Could nor persist work- null");
return Response.noContent().build();
} else{
Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HHmm:ssZ").create();
WorkDto dto = gson.fromJson(wo, WorkDto.class);
Work workDao = WorkTransformator.transform(dto);
workDao.persist();
return Response.ok().build();
}
}
Thanks again António for your help!

Resources