How to create a web service in Sitecore - asp.net

There is a tabbed panel like HTML in the page, where each tab click will show different data.
Trying to accomplish this with Ajax calls.
In the Visual studio project, I created a web service test.asmx, inside Services folder. So on publish, it is saved at wwwroot/MyApp/Website/Services/test.asmx
asmx.cs
[System.Web.Script.Services.ScriptService]
public class test : System.Web.Services.WebService
{
[WebMethod]
public string HelloWorld()
{
return "Hello World";
}
}
ascx
<asp:ScriptManager ID="_scriptManager" runat="server">
<Services>
<asp:ServiceReference Path="/Services/test.asmx" />
</Services>
</asp:ScriptManager>
<script type="text/javascript">
jQuery(function ($) {
console.log("howdy"); //this does print
var Param1 = 'one';
var Param2 = 'two';
$.ajax({
type: "GET",
url: "/Services/test.asmx/HelloWorld",
data:"",
contentType: "application/json; charset=utf-8",
dataType: "json",
async: "true",
cache: "false",
success: function (msg) {
alert(msg.d);
},
Error: function (x, e) {
alert("errrrr");
}
});
});
</script>
On browsing the page, there is this error in the browser console.
GET http://MyApp/Services/test.asmx/HelloWorld 500 (Internal Server
Error) jQuery.noconflict.js:16
Is this the right way to make the call
Is it because of the prototype.js conflict (not again !!). I already said jQuery(function ($) {..., but still.....

Personally I wouldn't use a web service because I dont think you are going to have the right Sitecore context for doing Sitecore work. I would just use MVC route and use it like an web api.
The controller
using System.Web.Mvc;
using Bonfire.Kickfire.Analytics.Dto;
using Bonfire.Kickfire.Analytics.Models;
namespace Bonfire.Kickfire.Analytics.Controllers
{
public class VisitorController : Controller
{
[HttpGet]
public JsonResult VisitorDetailsJson()
{
var item = Sitecore.Context.Item;
var vi = new VisitorInformation();
var trackerDto2 = vi.GetTrackerDto();
return Json(trackerDto2, JsonRequestBehavior.AllowGet);
}
}
}
The route
using System.Web.Mvc;
using System.Web.Routing;
using Sitecore.Pipelines;
namespace Bonfire.Kickfire.Analytics.Pipelines.Initialize
{
public class InitRoutes : Sitecore.Mvc.Pipelines.Loader.InitializeRoutes
{
public override void Process(PipelineArgs args)
{
RouteTable.Routes.MapRoute(
"Profile", // Route name
"VisitorData", // URL with parameters
new {controller = "Visitor", action = "VisitorDetailsJSON"},
new[] {"Bonfire.Kickfire.Analytics.Controllers"});
}
}
}
The patch file
<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<pipelines>
<initialize>
<processor type="Bonfire.Kickfire.Analytics.Pipelines.Initialize.InitRoutes, Bonfire.Kickfire.Analytics"
patch:before="processor[#type='Sitecore.Mvc.Pipelines.Loader.InitializeRoutes, Sitecore.Mvc']"/>
</initialize>
</pipelines>
</sitecore>
</configuration>

Related

asp.net mvc 5 actionlink 404 error with Area

**I have an index.cshtml inside a path like TeacherArea/Home/Index where I have this following actionlink: **
#Html.ActionLink("Edit", "EditTeachers", "Home", new { Area = "TeacherArea", id = item.id }, new { })
The purpose is to edit simple table row data.
My Home Controller looks like this:
namespace DemoProject2MVC.Areas.TeacherArea.Controllers
[RouteArea("TeacherArea")]
[RoutePrefix("TeacherArea/Home")]
public class HomeController : Controller
{
return view();
}
[Route("EditTeachers")]
public ActionResult Edit(int id)
{
MyDBContext stn = new MyDBContext();
Teacher tchr = stn.Teacher.Where(a => a.id == id).FirstOrDefault();
return View(tchr);
}
** I also have set namespace in "TeacherAreaAreaRegistration" of the controller class present inside the area like the following:**
public class TeacherAreaAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "TeacherArea";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"TeacherArea_default",
"TeacherArea/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional },
new[] { "DemoProject2MVC.Areas.TeacherArea.Controllers" }
);
}
}
I also have my global.asax like this:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes);
DataAccessLayer.StartUpClass.Start();
}
My issue is:
The index action method is calling fine within this mentioned area. But the actionlink to call Edit Action method is throwing 404.
https://localhost:44336/TeacherArea/Home/EditTeachers/7
I may be a bit rusty on MVC, but I think that if you want to mix attribute-based area declarations/routing with area/route registration in startup you need to make sure you are registering stuff in the proper order.
Another thing I noticed was that you're never calling RouteTable.Routes.MapMvcAttributeRoutes(); in your startup -- is that intentional?
If you are using both Areas with route attributes, and areas with convention based routes (set by an AreaRegistration class), then you need to make sure that area registration happen after MVC attribute routes are configured, however before the default convention-based route is set. The reason is that route registration should be ordered from the most specific (attributes) through more general (area registration) to the mist generic (the default route) to avoid generic routes from “hiding” more specific routes by matching incoming requests too early in the pipeline.
MSDN
Maybe you can try Ajax approach..
return $.ajax({
type: 'POST',
url: '<URL you want>',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
data: JSON.stringify({ Id: id}),
success: function (data) {
...
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
...
}
});
And your controller
[HttpPost]
public JsonResult EditTeachers(int Id)
{
MyDBContext stn = new MyDBContext();
Teacher tchr = stn.Teacher.Where(a => a.id == id).FirstOrDefault();
return Json(tchr, JsonRequestBehavior.AllowGet);
}
It might be easier to debug because you can see the where the Ajax request is going from this by inspecting the network.
Hope it helps

New to Angular. Trying to pass data back to server using angular / webapi

I am trying to pass data to server in angular using webapi. Thanks to people on the forum I was able to fill 1 drop down based on another using entity framework and angular. The next thing I wanted to figure out was how to pass screen data back to the server using webapi.
When the angular code is being called I am getting an error: badreq 'Http request configuration must be an object'
This error shows in the $http
I found an example online where it shows the ability of creating a parent model used by each of the html controls. In the case of the example online they were using textboxes, but I am using select lists, but I assume this should also work.
Can someone please tell me what I am doing wrong?
I appreciate it!!
FOLLOW UP: The problem I am having at this point seems to be that Data in the Angular saveattributecontroller states as UNDEFINED. So the issue I don't believe at this point is the call to the webapi, but the data not being passed from "Detail" in the HTML.
FOLLOW UP 2: based on Lorenzo's comment below. By putting the attributevaluecontroller around the submit button, I can now see the data passed to the saveattributecontroller in the attribute.js which is good. I also realized I needed to reference Data.A and Data.V in the saveattributecontroller. But now it seems the call to the WebAPIAttribute controller is not happening. I tried both the way I originally had and the other way that was suggested earlier yet the call to the controller never seems to go through. Can anyone help me with that?
Follow UP 3: The error I am finding as I step through the angular javascript is Resource can't be found. So I am assuming it is not finding the webapi controller for some reason. It's probably something very simple, but I am not seeing it.
var myapp = angular.module('attributeapp', []);
myapp.controller('attributecontroller', function ($scope, $http) {
$http.get('/Attribute/AttributeIndex/').then(function (response) {
$scope.Attributes = response.data;
})
})
myapp.controller('attributevaluecontroller', function ($scope, $http) {
$scope.getattributevalues = function (id)
{
$http.get('/Attribute/getattributevalues/' + id).then(function (response) {
$scope.A = id;
$scope.AttributeValues = response.data;
})
}
})
myapp.controller('saveattributecontroller', function($scope, $http){
$scope.attributesave = function (Data) {
var GetAll = new Object();
GetAll.AttributeKey = Data.AttributeKey;
GetAll.AttributeValueKey = Data.AttributeValueKey;
$http({
url: "WebAPIAttribute/attributesave",
dataType: 'json',
method: 'POST',
data: GetAll,
headers: {
"Content-Type": "application/json"
}
}).success(function (response) {
$scope.value = response;
})
.error(function (error) {
alert(error);
});
}
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script src="Scripts/angular.js"></script>
<script src="Scripts/attribute.js"></script>
</head>
<body data-ng-app="attributeapp">
<div data-ng-controller="attributecontroller">
<span data-ng-controller="attributevaluecontroller">
<select data-ng-model="detail.A" data-ng-change="getattributevalues(detail.A)" data-ng-options="Attribute.Attribute_Key as Attribute.Attribute_Desc for Attribute in Attributes"><option value="">--Select--</option></select><br />{{detail.A}}
<select data-ng-model="detail.V" data-ng-options="Attribute_Value.Attribute_Value_Key as Attribute_Value.Attribute_Value_Desc for Attribute_Value in AttributeValues"><option value="">--Select--</option></select>{{detail.V}}
</span>
<br />
<span data-ng-controller="saveattributecontroller">
<input type="button" value="submit" data-ng-click="attributesave(detail)"/>
</span>
</div>
</body>
</html>
//AttributeControler.cs
using System;
using System.Collections.Generic;
using MVC_APP1.Models;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MVC_APP1.Controllers
{
public class AttributeController : Controller
{
//
// GET: /Attribute/
public ActionResult AttributeIndex()
{
Cafe_CPDEntities objEntity = new Cafe_CPDEntities();
var data = objEntity.Attributes.ToList();
return Json(data, JsonRequestBehavior.AllowGet);
}
public ActionResult getattributevalues(int id)
{
Cafe_CPDEntities objEntity = new Cafe_CPDEntities();
var data = objEntity.Attribute_Value.Where(m=>m.Attribute_Key==id);
//string test = data.FirstOrDefault().Attribute_Value_Desc;
return Json(data, JsonRequestBehavior.AllowGet);
}
public ActionResult attributesave(List<int> ReturnData)
{
return null;
}
}
}
// WebAPIAttributeController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
namespace MVC_APP1.Controllers
{
public class WebAPIAttributeController : ApiController
{
public class GetAll
{
public string AttributeKey { get; set; }
public string AttributeValueKey { get; set; }
}
[HttpPost]
public string attributesave(HttpRequestMessage request,
[FromBody] GetAll getAll)
{
return "Data Reached";
}
}
}
Try to
$scope.attributesave = function (Data) {
var GetAll = new Object();
GetAll.AttributeKey = Data.AttributeKey;
GetAll.AttributeValueKey = Data.AttributeValueKey;
$http.post("WebAPIAttribute/attributesave", getAll)
.then(function(response){
//here your operations
})
}
(I THOUGHT I POSTED THIS EARLIER, BUT IT DID NOT SAVE)
I figured out the last part. I needed to add api/ to the route.
api/WebAPIAttributes/attributesave/
The call to webapi now goes through and passes the data from the screen.
Thanks so much to all those who helped answer the earlier issues I was having.

Create New Asmx Page in asp.net

I am creating an asmx web service.
In visual studio 2012 on the project name I right clicked and added an web service name UserDetails.asmx
Now I am trying to use the web service in the js file. like this
$.ajax({
type: "POST",
url: "UserDetails.asmx/HelloWorld",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data) {
alert('success');
},
error: function () {
alert("Error");
}
});
Its showing error that POST http: //192.168.9.185/GPS/UserDetails.asmx/HelloWorld 500 (Internal Server Error)
Is there any fault in my code or I am missing something so that its showing error.
My Asmx Page
<%# WebService Language="C#" CodeBehind="~/App_Code/UserDetails.cs" Class="UserDetails" %>
My Code Behind
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
/// <summary>
/// Summary description for UserDetails
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
// [System.Web.Script.Services.ScriptService]
public class UserDetails : System.Web.Services.WebService {
public UserDetails () {
//Uncomment the following line if using designed components
//InitializeComponent();
}
[WebMethod]
public string HelloWorld() {
return "Hello World";
}
}
Edit
Short Answer: just uncomment [System.Web.Script.Services.ScriptService]
Digging deep in the error message by using
error: function (xhr,status, error) {
alert("Error");
}
and inspecting xhr revealed that the actual error was something else (Only Web services with a [ScriptService] attribute on the class definition can be called from script).
I used [WebMethod] in my aspx code behind and whenever I received such message, I found out that there was an error in the data I am passing. So try adding data:"{}", in your $.ajax()
as described in this post
When making a read-only request, the empty data parameter is the key. For reasons unknown, jQuery does not properly set the specified content-type when there is no data included.

How to Call Default.aspx.cs page method from Jquery Ajax?

I have a registration form(Default.aspx) which initially show's only 2 field's and a button (Name, email) when user click's on button Jquery makes an Ajax call to Default.aspx.cs function which query db to check for the user, and if it return no then the form expands itself adding registration fields.
I am not able to make a call to Defualt.aspx.cs
my Default.aspx code is :
<script type="text/javascript">
$(document).ready(function() {
$('#btnDownload').click(function() {
//$('#secondary').toggle(1000)
$.ajax({
type: "POST",
url: "Default.aspx/PassData",
data: "{}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: AjaxSucceeded,
error: AjaxFailed
});
});
function AjaxSucceeded(result) {
alert(result.d);
}
function AjaxFailed(result) {
alert('Failed');
}
});
</script>
And Default.aspx.cs is (for test purpose) :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
private static string PassData(string id)
{
return "Pass";
}
}
But every-time I run the code JS returns error :
Uncaught ReferenceError: com is not defined
POST http://localhost:2305/temp/Default.aspx/PassData 500 (Internal Server Error)
I check few posts but non of them had been answered/resolved.
Any kind of help would be highly appreciated.
Thanks in advance
You need to decorate the method with [WebMethod] attribute.
EDIT
You'll need to add a ScriptManager and use some ASP.NET ajax framework methods. I think what you want to do is impossible with the out-of-the-box functionality.
One option will be to create a HttpHandler that will handle those methods. If the request is a POST, you can find the page type from the url (there's a method in the framework but I can't remember which one, you'll need to investigate), create a new instance and check if the method has the WebMethod (or another attribute you like). If it does, you can call it using reflection and render the result.
EDIT
As #Antony Highsky pointed out, it's possible. I think the solution is to add the [WebMethod] attribute and make de method public (it's private in the example).
Use **[WebMethod]
[WebMethod]
private static string PassData(string id)
{
return "Pass";
}

ASP.NET jQuery error: Unknown Web Method

This is my first time attempting to call an ASP.NET page method from jQuery. I am getting a status 500 error with the responseText message that the web method cannot be found. Here is my jQuery $.ajax call:
function callCancelPlan(activePlanId, ntLogin) {
var paramList = '{"activePlanId":"' + activePlanId + '","ntLogin":"' + ntLogin + '"}';
$.ajax({
type: "POST",
url: "ArpWorkItem.aspx/CancelPlan",
data: paramList,
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function() {
alert("success");
},
error: function(xml,textStatus,errorThrown) {
alert(xml.status + "||" + xml.responseText);
}
});
}
And here is the page method I am trying to call:
[WebMethod()]
private static void CancelPlan(int activePlanId, string ntLogin)
{
StrategyRetrievalPresenter presenter = new StrategyRetrievalPresenter();
presenter.CancelExistingPlan(offer, ntLogin);
}
I have tried this by decorating the Web Method with and without the parens'()'. Anyone have an idea?
Your web method needs to be public and static.
Clean the solution and rebuild. I've seen webmethods throw 500's until you do this.
Add public static before your method...
ex.
[WebMethod]
public static string MethodName() {}
For ajax success:
For me, it was helpful to make:
App_Start\RouteConfig
set
from
settings.AutoRedirectMode = RedirectMode.Permanent;
to
settings.AutoRedirectMode = RedirectMode.Off;
make your using method:
public
static
add:
using System.Web.Services;
and on top of method using just:
[WebMethod]
is enough
First Of All Don't Forget To Include
using System.Web.Services;
And Make Sure Your Method Should Be Public And Static and avoid adding Multiple Scripts in same Page like jquerymin.js shouldn't be used for every Function/Method in same Page
[WebMethod]
public static sting MethodName(){}
I Had The Same Issue Which Using Ajax And Jquery To Check Username Exists
Or Not.

Resources