Jquery Ajax call to WCF ajax enabled web service not working on Firefox - wcf

I have created a WCF ajax enabled web service named "Service1.svc"
"I have to call this Service In another app's using Jquery."
I have created on method in it :
[OperationContract]
public string GetMarkup()
{
string data = "<div>My HTML markup text here</div>";
return data;
}
Now I have created jquery script in my second application's html page :
var markup = "";
$.ajax({
type: "POST",
url: "http://localhost:1676/MyWCFService.svc/GetMarkup",
contentType: "application/json",
data: "{}",
dataType: "json",
success: callback,
error: function (textStatus) {
alert("ERROR");
}
});
function callback(result) {
alert("Inside Callback");
markup = result.d;
$("#divMyMarkup").html(markup);
alert(markup);
}
NOW, My Problem is that Whenever I execute this page in IE its working fine.
But In Firefox its not working. It giving alert Error Message which defined in
error: function (textStatus) {alert("ERROR");} in above ajax call.
I tried this functionality using $.get(), $("#divMyMarkup").load(serviceUrl, callback).
I also tried this by changing the datatype as json, jsonp, html .
Still I am not getting the exact solution.
Any Expert here?

In another app's using Jquery
In my experience, IE won't respect the cross-domain policy and let you do the call, not a reference...
The only way to find out is to have your html page/JQuery script calling your WCF service from http://localhost:1676/ICallWcfServicesWithJQuery.html on Firefox.
Possible solutions:
[JSONP] how to avoid cross domain policy in jquery ajax for consuming wcf service?
[flXHR][php-proxy] jQuery “getJSON” from an external domain that doesn't support JSON-P output
[JSONP] Accessing web Service from jQuery - cross domain
[.net-proxy] aspnet-proxy-page-cross-domain-requests-from-ajax-and-javascript
Test on multiple browsers, add 1oz of gin, a can of tonic and you'll be good!

Related

ASP.NET Core: POSTing complex type from jQuery always results in 'null' model

I'm trying to POST to my ASP.NET Core (RC1) API from jQuery. It works fine when I POST via HttpClient, so I think it's only a stupid thing I'm missing.
I can reproduce my problem on a vanilla default ASP.NET 5 project and this code.
Server
namespace WebApplication1.Controllers
{
[Route("api/[controller]")]
public class ValuesController : Controller
{
[HttpPost]
public IActionResult Post([FromBody]Model input)
{
// input is always null
return Json(input.Value);
}
public class Model
{
public string Value { get; set; }
}
}
}
Client
$.ajax({
url: "http://localhost:5000/api/values",
method: "POST",
contentType: "application/json",
dataType: "json",
data: JSON.stringify({
Value: "some_value"
})
}).done(function(data) {
console.log("Done.", data);
});
I played around by removing [FromBody], that returns a model, but the properties were never populated. I also tried the many solutions and workarounds for similar problems on SO, but I think they don't apply to .NET Core or only solve problems usinf [FromBody] and simple types. For example Web Api Parameter always null or using jQuery post to ASP.Net webapi or http://encosia.com/using-jquery-to-post-frombody-parameters-to-web-api/
I took another few hours until I finally figured it out. As I feared/hoped, it was only one stupid thing:
It took Fiddler to discover that I had minor problems with my CORS configuration. Realizing that I disabled CORS completely in Chrome and it suddenly started to work. The server-side code worked as-is, this is the minimal working client-side code:
$.ajax({
url: "http://localhost:5000/api/values",
method: "POST",
contentType: "application/json",
data: JSON.stringify({
value: "some_value"
})
}).done(function(data) {
console.log("Done.", data);
});
Please note that contentType is required, without it the modelbinding won't work.
Of course, I had tried this client-side code before, but CORS funked it up: There is an OPTION request for CORS to determine if the request is valid. The browser F12 tools don't make this as obvious as it should be. Interestingly I received the OPTION request in the debugger (and that's why I thought it worked), but I finally discovered via Fiddler that the contentType header was not correctly transmitted in these requests - and that's why the model was not bound correctly.

Set strongly typed view through Ajax or MVC controller?

I am new to MVC and we are building a MVC application having razor views and Web API controller for fetching data from Repository layer.
Now, we have a login screen and after successful authentication we want to redirect the user to Accounts page which is strongly typed. For authenticating credentials we make an Ajax call on button click and based on results, we display an error message or perform the redirection in Ajax’s success method.
$.ajax({
type: 'post',
url: '/api/User/Authenticate',
datatype: 'json',
success: function (isValid) {
if (isValid)
window.location.href = "/User/Account";
},
failure: OnFailure
});
We are confused about the redirection and data fetching implementation. As mentioned, Account page is strongly typed view with 'UserAccount' entity. I want to populate this entity and then directly send it to Accounts page so that I can powerfully use the feature of Model binding.
We have found two approaches to do this:
Call the Web API controller inside MVC controller belonging to Accounts page.
public ActionResult Account()
{
AccountsAPIController account = new AccountsAPIController();
UserAccount userAccount = account.GetAccountsDetails(234);
return View(userAccount);
}
Fetch data on Account pages load and then manually assign each Entities property to respective controls. This works but then it overlooks the concept of strongly typed views.
$.ajax({
type: 'get',
url: '/api/AccountsAPI/ GetAccountsDetails,
datatype: 'json',
data: {'userID': 234},
contentType: 'application/json; ',
success: function (data) {
// Assign data value to each and every control
$('#First_Name').val(data.First_Name);
$('#Phone_Number').val(data.Phone_Number);
// ..
},
failure: OnFailure
});
Please suggest which method is correct or is there any standard approach we can go with.
Thanks for your time.
I find myself referring back to this article on CodeProject many times (the article is too large to replicate here).
It shows you how to create a normal form on a page using Html.BeginForm(), then how to convert it to use Ajax.BeginForm(). This allows you to submit a small portion of the page using AJAX, whilst being able to still use strongly-typed models, model binding and all the model validation attribute goodness of MVC (including all the Html.TextBoxFor(), Html.ValidationMessageFor() helpers etc.).

page Redirect in ASP.Net MVC + Web Api + AngularJs

I am building a ASP.Net MVC application that can work both in Web and JQuery mobile. So i am creating a seperate view for Web and JQuery mobile application. I have placed all my primary business logic services as a Web Api calls which are called by both the clients using the AngularJs which is working fine so far.
Now I was looking to introduce the security in to the application, and realized that Basic authentication is the quickest way to get going and when I looked around I found very nice posts that helped me build the same with minimal effort. Here are 3 links that I primarily used:
For the Client Side
HTTP Auth Interceptor Module : a nice way to look for 401 error and bring up the login page and after that proceed from where you left out.
Implementing basic HTTP authentication for HTTP requests in AngularJS : This is required to ensure that I am able reuse the user credentials with the subsequent requests. which is catched in the $http.
On the Server Side :
Basic Authentication with Asp.Net WebAPI
So far so good, all my WebApi calls are working as expected,
but the issue starts when I have to make calls to the MVC controllers,
if I try to [Authorize] the methods/controllers, it throws up the forms Authentication view again on MVC even though the API has already set the Authentication Header.
So I have 2 Questions:
Can We get the WebApi and MVC to share the same data in the header? in there a way in the AngularJS i can make MVC controller calls that can pass the same header information with authorization block that is set in the $http and decode it in the server side to generate my own Authentication and set the Custom.
In case the above is not possible, I was trying to make a call to a WebApi controller to redirect to a proper view which then loads the data using the bunch of WebApi calls so that user is not asked to enter the details again.
I have decorated it with the following attribute "[ActionName("MyWorkspace")] [HttpGet]"
public HttpResponseMessage GotoMyWorkspace(string data)
{
var redirectUrl = "/";
if (System.Threading.Thread.CurrentPrincipal.IsInRole("shipper"))
{
redirectUrl = "/shipper";
}
else if (System.Threading.Thread.CurrentPrincipal.IsInRole("transporter"))
{
redirectUrl = "/transporter";
}
var response = Request.CreateResponse(HttpStatusCode.MovedPermanently);
string fullyQualifiedUrl = redirectUrl;
response.Headers.Location = new Uri(fullyQualifiedUrl, UriKind.Relative);
return response;
}
and on my meny click i invoke a angular JS function
$scope.enterWorkspace = function(){
$http.get('/api/execute/Registration/MyWorkspace?data=""')
.then(
// success callback
function(response) {
console.log('redirect Route Received:', response);
},
// error callback
function(response) {
console.log('Error retrieving the Redirect path:',response);
}
);
}
i see in the chrome developer tool that it gets redirected and gets a 200 OK status but the view is not refreshed.
is there any way we can at least get this redirect to work in case its not possible to share the WebApi and MVC authentications.
EDIT
Followed Kaido's advice and found another blog that explained how to create a custom CustomBasicAuthorizeAttribute.
Now I am able to call the method on the Home controller below: decorated with '[HttpPost][CustomBasicAuthorize]'
public ActionResult MyWorkspace()
{
var redirectUrl = "/";
if (System.Threading.Thread.CurrentPrincipal.IsInRole("shipper"))
{
redirectUrl = "/shipper/";
}
else if(System.Threading.Thread.CurrentPrincipal.IsInRole("transporter"))
{
redirectUrl = "/transporter/";
}
return RedirectToLocal(redirectUrl);
}
Again, it works to an extent, i.e. to say, when the first call is made, it gets in to my method above that redirects, but when the redirected call comes back its missing the header again!
is there anything I can do to ensure the redirected call also gets the correct header set?
BTW now my menu click looks like below:
$scope.enterMyWorkspace = function(){
$http.post('/Home/MyWorkspace')
.then(
// success callback
function(response) {
console.log('redirect Route Received:', response);
},
// error callback
function(response) {
console.log('Error retrieving the Redirect path:',response);
}
);
}
this finally settles down to the following URL: http://127.0.0.1:81/Account/Login?ReturnUrl=%2fshipper%2f
Regards
Kiran
The [Authorize] attribute uses forms authentication, however it is easy to create your own
BasicAuthenticationAttribute as in your third link.
Then put [BasicAuthentication] on the MVC controllers instead of [Authorize].

How to call a service reference from jquery?

I have added a service reference to my asp.net web application (originally it was just a straight html site and we converted it to a web application)
We need to access a WCF service via jquery/ajax and not from within any .cs files. So far we haven't been able to get jquery to hit the service by any means, even before it was converted to a web app (converted in hopes that it would be easier to add service reference and call it)
I have the WCF service running in a separate solution running on my desktop and the web app open separately. My service is called SchoolService and is located in the Service References folder.
How in jquery do I call that service reference?
This is what we used from a demo that also did not work:
<script type="text/javascript">
$(document).ready(function () {
var schoolsCache = {}, lendersCache = {}, schoolsXhr, lendersXhr;
$('#Schools').autocomplete({
source: function (request, response) {
var term = request.term;
if (term in schoolsCache) {
response(schoolsCache[term]);
return;
}
if (schoolsXhr != null) {
schoolsXhr.abort();
}
schoolsXhr = $.getJSON('SchoolService.svc/GetSchools', request, function (data, status, xhr) {
schoolsCache[term] = data.d;
if (xhr == schoolsXhr) {
response(data.d);
schoolsXhr = null;
}
});
}
});
});
</script>
I have also tried this line which did not work:
schoolsXhr = $.getJSON('http://localhost:8000/SchoolService/GetSchools', request, function (data, status, xhr) {
Here is the interface in my WCF sdervice:
using System.Collections.Generic;
using System.ServiceModel;
using System.ServiceModel.Web;
using MyApp.DomainModel;
namespace MyAppService
{
[ServiceContract]
public interface ISchoolService
{
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Json)]
IList<School> GetSchools(string term);
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Json)]
School GetSchool(string schoolName);
}
}
What are the necessary specific steps needed to make this work? The goal is to let user type into textbox, use jquery autocomplete, which uses the ajax call to service to pull back data that contains the typed text... surely this has been done before?
CD
You can take a look at this CodeProject article. The author is discussing exactly this profile a WCF service and JQuery client.
No one was able to answer this but we figured it out. It had nothing to do with jsonp or cross domain.
The call from javascript makes a $.getJSON call to the url. The url is the relative url to a .svc file in the project. The .svc file is nothing more than a passthru which constructs a connection to the referenced service and makes the call and then returns back to the ajax call.

Accessing webmethod with jquery

I'm currently using jquery ajax to call a pagemethod (which works great);
$.ajax({
type: "POST",
url: "ArticleList.aspx/GetArticleTags",
data: "{'articleId' : " + articleId + "}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (msg) {
if (msg.hasOwnProperty("d")) { msg = msg.d; }
var tags = JSON.parse(msg);
//do something
}
});
The pagemethod;
<WebMethod()>
Public Shared Function GetArticleTags(ByVal articleId As Integer) As String
Using myDb As New MyRepository
Dim js As New JavaScriptSerializer
Dim returnString = js.Serialize((From t In myDb.GetArticleTags(articleId) Select t.TagId, t.Tag).ToList)
Return returnString
End Using
End Function
I'm now in the position, where i need to access my GetArticleTags function from multiple pages. To quickly get it up and running i could
Copy the function to my new aspx page, and call it in the same way.
Continue to point to the original aspx page.
Both of which are pretty rubbish.
So the only reasonable way left is to call a wcf (webget) method.
This will have the benefit of meaning i won't have to manually serialize the objects to json. It'll be done for me.
I do have a restful webservice in the solution already, but i'm wary about calling it from my webapp. I'd rather all the code live within my webapp, not depend on a web service which will be in a different app pool on the same iis server. It may need to be cold-started etc, and i need this to be quick.
I've added a wcf file to my webapp using the template "AJAX-enabled WCF Service". But then by doing this, i'm muddying up my webapp with endpoints in the web.config etc. (and i'm currently getting 500 System.ServiceModel.ServiceActivationException exception's)
So, down to my question....
What's the best way to call my function? (I'm thinking it has to be my restful webservice)
Is there another option that i'm not considering?
Thanks muchly.
You should make an AJAX-enabled ASMX service or use an ordinary ASHX handler.
If you make an ASHX handler, you'll need to handle parsing and security yourself; I recommend an ASMX service, which can be extremely similar to your page method.