DotNetNuke7:-Web Api is not triggering on call - asp.net-web-api

I have implemented a module using Angular Js and TypeScript in DotNetNuke7 where i have implemented my all Input Forms and js in a web project named as customerNew and than added a Web APi into a another project named as CustomerNewController which is having my methods but when i hit the URL from my Web Project to Api.It doesn't processed.I have implemented a route mapper as well but still not able get success.
My Route Mapper Class is Given Below:-
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DotNetNuke.Web.Api;
using System.Web.UI.WebControls;
namespace CustomerNewController
{
class RouteMapper : IServiceRouteMapper
{
public void RegisterRoutes(IMapRoute mapRouteManager)
{
mapRouteManager.MapHttpRoute("CustomerNewController", "default", "{controller}/{action}",
new[] { "CustomerNewController" });
}
}
}
Here is my WebApi
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web;
using System.Configuration;
using System.Data.SqlClient;
using System.Data;
using System.Collections;
using System.Web.UI;
using System.Xml.Serialization;
using DotNetNuke.Entities.Users;
using System.Web.Services;
using DotNetNuke.Web.Api;
using DotNetNuke.Common.Utilities;
using DotNetNuke.Entities.Modules.Communications;
using DotNetNuke.Entities.Modules;
namespace CustomerNewController
{
public class CreateController : DnnApiController
{
[AllowAnonymous]
[HttpGet]
public HttpResponseMessage HelloWorld()
{
return Request.CreateResponse(HttpStatusCode.OK, "Hello World!");
}
}}
My URL
http://localhost/dnn7/DesktopModules/CustomerNewController/Api/Create/HelloWorld
Here is my folder structure

An example of my WebAPI GET method:
[DnnExceptionFilter]
public class AuthorController : DnnApiController
{
#region Public RPC Methods
[HttpGet]
[AllowAnonymous]
public HttpResponseMessage GetAllAuthors()
{
var lstAuthors = AuthorRepository.GetAllAuthors();
return Request.CreateResponse(HttpStatusCode.OK, lstAuthors);
}
[HttpGet]
[AllowAnonymous]
public HttpResponseMessage GetAlphabet()
{
var lstAuthors = AuthorRepository.GetAlphabet();
return Request.CreateResponse(HttpStatusCode.OK, lstAuthors);
}
#endregion
}
Service route mapper example (only need to do this once):
public class ServiceRouteMapper : IServiceRouteMapper
{
#region IServiceRouteMapper Implementation
public void RegisterRoutes(IMapRoute mapRouteManager)
{
mapRouteManager.MapHttpRoute("ATKV.Commerce", "default", "{controller}/{action}", new[] { "ATKV.Commerce.Services" });
}
#endregion
}
Calling code:
// Service Paths
var servicesFramework = opts.servicesFramework;
var servicePath = servicesFramework.getServiceRoot('ATKV.Commerce') + 'Author/';
// Bind data
$.ajax({
type: "GET",
cache: false,
url: servicePath + "GetAllAuthors",
beforeSend: servicesFramework.setModuleHeaders
}).done(function (authors) {
if (typeof authors !== "undefined" && authors != null) {
var viewModel = new MasterViewModel(authors);
ko.applyBindings(viewModel, document.getElementById($(containerElement).attr('id')));
} else {
displayMessage("An error occurred", "dnnFormError");
}
}).fail(function (xhr, status) {
displayMessage(status, "dnnFormError");
return null;
});

Related

Update cache upon modified entity

I am using IMemoryCache and running an asp-net core project. On the home page I have listed some movies, which are cached for like 10 minutes. Is there a way to update the cache, If a movie has been created/deleted/edit, If if those 10 minutes have not passed?
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;
using MovieManagement.Models;
using MovieManagement.Models.Home;
using MovieManagement.Services.Contracts;
using MovieManagement.ViewModels;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
namespace MovieManagement.Controllers
{
public class HomeController : Controller
{
private readonly IMovieService movieService;
private readonly IMemoryCache cacheService;
public HomeController(IMovieService movieService, IMemoryCache cache)
{
this.movieService = movieService ?? throw new ArgumentNullException(nameof(movieService));
this.cacheService = cache ?? throw new ArgumentNullException(nameof(cache));
}
public async Task<IActionResult> Index()
{
var model = new HomeIndexViewModel();
var cachedMovies = await this.cacheService.GetOrCreateAsync("Movies", async entry =>
{
entry.AbsoluteExpiration = DateTime.UtcNow.AddSeconds(20);
var movies = await this.movieService.GetTopRatedMovies();
return movies;
});
model.Movies = cachedMovies;
return this.View(model);
}
}
}
You could update the cached values on Delete/Create/Edit via a shared private method:
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;
using MovieManagement.Models;
using MovieManagement.Models.Home;
using MovieManagement.Services.Contracts;
using MovieManagement.ViewModels;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
namespace MovieManagement.Controllers
{
public class HomeController : Controller
{
private readonly IMovieService movieService;
private readonly IMemoryCache cacheService;
public HomeController(IMovieService movieService, IMemoryCache cache)
{
this.movieService = movieService ?? throw new ArgumentNullException(nameof(movieService));
this.cacheService = cache ?? throw new ArgumentNullException(nameof(cache));
}
public async Task<IActionResult> Index()
{
var model = new HomeIndexViewModel();
var cachedMovies = await this.cacheService.GetOrCreateAsync("Movies", async entry =>
{
entry.AbsoluteExpiration = DateTime.UtcNow.AddMinutes(10);
var movies = await this.movieService.GetTopRatedMovies();
return movies;
});
model.Movies = cachedMovies;
return this.View(model);
}
[HttpPost]
public async Task<IActionResult> Delete(int id)
{
this.movieService.Delete(id);
UpdateCachedMovies();
return RedirectToAction(nameof(Index));
}
[HttpPost]
public async Task<IActionResult> Create(Movie model)
{
this.movieService.Add(model);
UpdateCachedMovies();
return RedirectToAction(nameof(Index));
}
private async void UpdateCachedMovies()
{
this.cacheService.Set("Movies", this.movieService.GetTopRatedMovies(), DateTime.UtcNow.AddMinutes(10));
}
}
}

Xamarin MVVM passing data to other view

I want to pass the data to another view page. So far I can get the data I need to pass. My problem is how do I pass the data in MVVM. I used Application.Current.MainPage.Navigation.PushAsync(new DatabaseSyncPage(), true); When I add contactId inside DatabaseSyncPage() an error occurs. "The error is 'DatabaseSyncPage' does not contain a constructor that takes 1 arguments"
My code:
LoginPageViewModel.cs
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Net;
using System.Text;
using System.Windows.Input;
using TBSMobileApplication.Data;
using TBSMobileApplication.View;
using Xamarin.Essentials;
using Xamarin.Forms;
namespace TBSMobileApplication.ViewModel
{
public class LoginPageViewModel : INotifyPropertyChanged
{
void OnProperyChanged(string PropertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
}
public string username;
public string password;
public string Username
{
get { return username; }
set
{
username = value;
OnProperyChanged(nameof(Username));
}
}
public string Password
{
get { return password; }
set
{
password = value;
OnProperyChanged(nameof(Password));
}
}
public class LoggedInUser
{
public string ContactID { get; set; }
}
public ICommand LoginCommand { get; set; }
public LoginPageViewModel()
{
LoginCommand = new Command(OnLogin);
}
public void OnLogin()
{
if (string.IsNullOrEmpty(Username) || string.IsNullOrEmpty(Password))
{
MessagingCenter.Send(this, "Login Alert", Username);
}
else
{
var current = Connectivity.NetworkAccess;
if (current == NetworkAccess.Internet)
{
var link = "http://192.168.1.25:7777/TBS/test.php?User=" + Username + "&Password=" + Password;
var request = HttpWebRequest.Create(string.Format(#link));
request.ContentType = "application/json";
request.Method = "GET";
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
if (response.StatusCode != HttpStatusCode.OK)
{
Console.Out.WriteLine("Error fetching data. Server returned status code: {0}", response.StatusCode);
}
else
{
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
var content = reader.ReadToEnd();
if (content.Equals("[]") || string.IsNullOrWhiteSpace(content) || string.IsNullOrEmpty(content))
{
MessagingCenter.Send(this, "Http", Username);
}
else
{
var result = JsonConvert.DeserializeObject<List<LoggedInUser>>(content);
var contactId = result[0].ContactID;
Application.Current.MainPage.Navigation.PushAsync(new DatabaseSyncPage { myId = contactId }, true);
}
}
}
}
else
{
MessagingCenter.Send(this, "Not Connected", Username);
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
}
DatabaseSyncPage.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace TBSMobileApplication.View
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class DatabaseSyncPage : ContentPage
{
public int myId { get; set; }
public DatabaseSyncPage ()
{
InitializeComponent ();
DisplayAlert("Message", Convert.ToString(myId), "ok");
}
}
}
If you want to send the int. First declare that in your DatabaseSyncPage
Like below
public partial class DatabaseSyncPage : ContentPage
{
public DatabaseSyncPage( int Id)
{
}
}
& when you are pushing your page in your code else block do like this
if (content.Equals("[]") || string.IsNullOrWhiteSpace(content) || string.IsNullOrEmpty(content))
{
MessagingCenter.Send(this, "Http", Username);
}
else
{
var result = JsonConvert.DeserializeObject<List<LoggedInUser>>(content);
var contactId = result[0].ContactID;
Application.Current.MainPage.Navigation.PushAsync(new DatabaseSyncPage(contactId), true);
}
I'm assuming that contactID is an int.
Create an additional constructor in your DatabaseSyncPage:
public DatabaseSyncPage (int contactID)
{
// TODO: Do something with your id
}
But this passes the data to the page, not the page model.
Are you using any kind of framework? It would probably be worth looking into that.
You can use xamrin.plugins.settings nuget package.

Configuration.AddJsonFile("config.json") NullReferenceException

I take NullReferenceException when I want to add addJsonFile. I made exaclty what lynda(http://www.lynda.com/ASP-NET-tutorials/Dynamically-control-behavior-custom-configuration/368051/431234-4.html) said.
(screenShot)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNet.Diagnostics;
using Microsoft.Framework.Internal;
using Microsoft.Framework.ConfigurationModel;
using Microsoft.Framework.ConfigurationModel.Json;
namespace PortalDemo
{
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app)
{
var config = new Configuration();
config.AddEnvironmentVariables();
config.AddJsonFile("config.json");//Here
if (config.Get("debug") == "True")
{
app.UseRuntimeInfoPage();
app.UseDeveloperExceptionPage();
}
app.UseExceptionHandler("/home/errorPage");
app.UseMvc(routes=>
routes.MapRoute("Default","{controller=Home}/{action=Index}/{id?}"));
app.UseStaticFiles();
}
// Entry point for the application.
public static void Main(string[] args) => WebApplication.Run<Startup>(args);
}
}
Try the following code.
public class Startup
{
public Startup(IApplicationEnvironment appEnv)
{
IConfigurationBuilder builder = new ConfigurationBuilder()
.SetBasePath(appEnv.ApplicationBasePath)
.AddJsonFile("config.json", false);
Configuration = builder.Build();
}
public IConfiguration Configuration { get; set; }
}

Mock the business layer for integration testing the Web API

I want to do integration tests on my Web API without depending on my business layer interfaces.
When this action is run:
1) I want to mock the _service object and just verify that is is called
2) I want to assert that the correct StatusCode is returned
Number 2 is no problem but how can I mock the _service object (ISchoolyearService) when I do not control/start the creation of the api controller manually because this is a task done in unit testing the controller. But I do not want to unit test my API !
[RoutePrefix("api/schoolyears")]
public class SchoolyearController : ApiController
{
private readonly ISchoolyearService _service;
public SchoolyearController(ISchoolyearService service)
{
_service = service;
}
[Route("")]
[HttpPost]
public HttpResponseMessage Post([FromBody]SchoolyearCreateRequest request)
{
_service.CreateSchoolyear(request);
return Request.CreateResponse(HttpStatusCode.Created);
}
Following is a crude example of how you can do with in-memory integration testing. Here I am using Unity.WebApi.UnityDependencyResolver to inject mock dependencies. You can use any other IoC container similarly.
using Microsoft.Practices.Unity;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http;
using Unity.WebApi;
namespace WebApplication251.Tests.Controllers
{
[TestClass]
public class PeopleControllerTest
{
string baseAddress = "http://dummyhost/";
[TestMethod]
public void PostTest()
{
HttpConfiguration config = new HttpConfiguration();
// use the configuration that the web application has defined
WebApiConfig.Register(config);
//override the dependencies with mock ones
RegisterMockDependencies(config);
HttpServer server = new HttpServer(config);
//create a client with a handler which makes sure to exercise the formatters
HttpClient client = new HttpClient(new InMemoryHttpContentSerializationHandler(server));
SchoolyearCreateRequest req = new SchoolyearCreateRequest();
using (HttpResponseMessage response = client.PostAsJsonAsync<SchoolyearCreateRequest>(baseAddress + "api/schoolyears", req).Result)
{
Assert.IsNotNull(response.Content);
Assert.IsNotNull(response.Content.Headers.ContentType);
Assert.AreEqual<string>("application/json; charset=utf-8", response.Content.Headers.ContentType.ToString());
SchoolyearCreateRequest recSCR = response.Content.ReadAsAsync<SchoolyearCreateRequest>().Result;
//todo: verify data
}
}
private void RegisterMockDependencies(HttpConfiguration config)
{
var unity = new UnityContainer();
unity.RegisterType<ISchoolyearService, MockSchoolyearService>();
config.DependencyResolver = new UnityDependencyResolver(unity);
}
}
[RoutePrefix("api/schoolyears")]
public class SchoolyearController : ApiController
{
private readonly ISchoolyearService _service;
public SchoolyearController(ISchoolyearService service)
{
_service = service;
}
[Route]
[HttpPost]
public HttpResponseMessage Post([FromBody]SchoolyearCreateRequest request)
{
_service.CreateSchoolyear(request);
return Request.CreateResponse(HttpStatusCode.Created);
}
}
public class InMemoryHttpContentSerializationHandler : DelegatingHandler
{
public InMemoryHttpContentSerializationHandler(HttpMessageHandler innerHandler)
: base(innerHandler)
{
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
request.Content = await ConvertToStreamContentAsync(request.Content);
HttpResponseMessage response = await base.SendAsync(request, cancellationToken);
response.Content = await ConvertToStreamContentAsync(response.Content);
return response;
}
private async Task<StreamContent> ConvertToStreamContentAsync(HttpContent originalContent)
{
if (originalContent == null)
{
return null;
}
StreamContent streamContent = originalContent as StreamContent;
if (streamContent != null)
{
return streamContent;
}
MemoryStream ms = new MemoryStream();
await originalContent.CopyToAsync(ms);
// Reset the stream position back to 0 as in the previous CopyToAsync() call,
// a formatter for example, could have made the position to be at the end
ms.Position = 0;
streamContent = new StreamContent(ms);
// copy headers from the original content
foreach (KeyValuePair<string, IEnumerable<string>> header in originalContent.Headers)
{
streamContent.Headers.TryAddWithoutValidation(header.Key, header.Value);
}
return streamContent;
}
}
}

Error While adding Exception Filter in MVC 3

I am trying to create custom exceptions for my mvc 3(razor) application.
But its not working properly.
Following is the code I've written for custom exception class.
using System;
using System.Web.Mvc;
namespace TestApp.Helpers
{
public class CustomExceptionAttribute : FilterAttribute, IExceptionFilter
{
public void OnException(ExceptionContext filterContext)
{
if (!filterContext.ExceptionHandled && filterContext.Exception is Exception)
{
//filterContext.Result = new RedirectResult("/shared/Error.html");
filterContext.Result = new ViewResult { ViewName = "Error" };
filterContext.ExceptionHandled = true;
}
}
}
}
Below is the code in controller:
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Text;
using TestApp.Domain;
using TestApp.Helpers;
namespace TestApp.Controllers
{
[CustomException]
public class MyController : Controller
{
private TestAppEntities db = new TestAppEntities();
public ActionResult Create(int id)
{
// Throwing exception intentionally
int a = 1;
int b = 0;
int c = a / b;
//This is another method which is working fine.
return View(CreateData(id, null));
}
}
}
And below is the code in 'Error.cshtml'
#model System.Web.Mvc.HandleErrorInfo
#{
ViewBag.Title = "Error";
}
<h2>
Sorry, an error occurred while processing your request.
</h2>
<div>
<p>
There was a <b>#Model.Exception.GetType().Name</b> while rendering <b>#Model.ControllerName</b>'s
<b>#Model.ActionName</b> action.
</p>
<p>
The exception message is: <b><#Model.Exception.Message></b>
</p>
<p>Stack trace:</p>
<pre>#Model.Exception.StackTrace</pre>
</div>
When we run the application it throws the error at #Model.Exception.GetType().Name, because model is null.
This is the exact error: NullReferenceException: Object reference not set to an instance of an object.
Can anybody please let me know what can be the exact reason for the error?
How can I fix this?
You have to pass the HandleErrorInfo instance to the view.
string controllerName = (string)filterContext.RouteData.Values["controller"];
string actionName = (string)filterContext.RouteData.Values["action"];
HandleErrorInfo model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName);
filterContext.Result = new ViewResult
{
ViewName = "Error",
ViewData = new ViewDataDictionary<HandleErrorInfo>(model)
};

Resources