ASP.Net (3.5) MVC partial class for rule validation - asp.net

I have 2 projects. A data project, which contains my database and my Entity Framework model. I have table called 'User', and then have a generated EF class for user.
I am trying to add a partial class:
using System;
using System.Collections.Generic;
using System.Data.Linq;
using System.Linq;
using System.Text;
namespace Data
{
public partial class user
{
public bool isValid
{
get {
return (GetRuleViolations().Count()==0);
}
}
public IEnumerable<RuleViolation> GetRuleViolations()
{
yield break;
}
partialvoid OnValidate(ChangeAction action)
{
if (isValid)
throw new ApplicationException("Rule violation prevents saving");
}
}
public class RuleViolation
{
public string ErrorMessage { get; private set; }
public string PropertyName { get; private set; }
public RuleViolation (string errorMessage)
{
ErrorMessage = errorMessage;
}
public RuleViolation(string errorMessage, string propertyName)
{
ErrorMessage = errorMessage;
PropertyName = propertyName;
}
}
}
This is following the MVC 1.0 NerdDinner example. However, I am getting a design time error on the OnValidate method:
partial void OnValidate(ChangeAction action)
{
if (isValid)
throw new ApplicationException("Rule violation prevents saving");
}
No definining declaration found for implimenting declaration of partial method 'void OnValidate(ChangeAction action)'
What am I doing wrong?

There should be another file containing the rest of the user class.
In this file you have to declare that there might be a partial method called OnValidate.
public partial class user
{
partial void OnValidate(ChangeAction action);
}
Some detail:
A partial method needs to have a signature specified somewhere. Once the signature has been defined then an optional implementation can be specified. Read http://msdn.microsoft.com/en-us/library/wa80x488.aspx for more information.

Related

FluentValidation - PolymorphicValidator: How to avoid validator duplication?

I have an entity called "Role" in my asp.net core 6 Web API application. Below is the DTO of the "Role" entity
public class CreateUpdateRoleDto
{
public Guid Id { get; set; }
.....
}
and I have implemented the Command like mentioned below
public class CreateRoleCommand : CreateUpdateRoleDto, IRequest<Guid>
{
}
with the corresponding Validator
public class CreateRoleCommandValidator : AbstractValidator<CreateRoleCommand>
{
}
Now, I want to implement the batch processing for the same "Role" entity and I have implemented the Command like mentioned below
public class CreateRoleBatchCommand : CreateUpdateRoleDto, IRequest
{
}
with its validator
public class CreateRoleBatchCommandValidator : AbstractValidator<CreateRoleBatchCommand>
{
}
CreateRoleBatchCommandValidator is just a copy of the CreateRoleCommandValidator except that it implements IRequest instead of IRequest but I don't think we need this additional validator as this is just a duplicate code.
Below is the implementation of BatchCommand
public class BatchCommand : IRequest
{
public IEnumerable<IRequest> Requests { get; set; }
}
The batch command validator uses the PolymorphicValidator and sets CreateRoleBatchCommandValidator as a validator for CreateRoleBatchCommand.
public class BatchCommandValidator : AbstractValidator<BatchCommand>
{
public BatchCommandValidator()
{
this.RuleForEach(x => x.Requests).SetAsyncValidator(new PolymorphicValidator<BatchCommand, IRequest>()
.Add<CreateRoleBatchCommand>(new CreateRoleBatchCommandValidator()));
}
}
However, I want to set CreateRoleCommand as a validator for CreateRoleBatchCommand, something like this
public class BatchCommandValidator : AbstractValidator<BatchCommand>
{
public BatchCommandValidator()
{
this.RuleForEach(x => x.Requests).SetAsyncValidator(new PolymorphicValidator<BatchCommand, IRequest>()
.Add<CreateRoleBatchCommand>(new CreateRoleCommandValidator()));
}
}
However it throws the following error.
CS1503 Argument 1: cannot convert from 'CreateRoleCommandValidator' to
'FluentValidation.IValidator'

Uno Platform WASM SignalR deserialization issues

I have a SignalR service and an Uno Platform WASM Client (with Prism). I want to call a hub method, which returns a model. The problem is, i have two identical models (Properties, Methods, etc.) but the client can only receive one of them upon calling the hub methods. With the other model a exception gets thrown on deserialization.
Hub:
using Microsoft.AspNetCore.SignalR;
using ReservationManagement.SignalRInterface.Model;
using System.Threading.Tasks;
namespace ReservationManagement.Service.Hubs
{
public class TestServiceHub: Hub
{
public async Task<LocationModel> LocationModel()
{
return new LocationModel() { Name = "Location" };
}
public async Task<TestModel> TestModel()
{
return new TestModel() { Name = "Test" };
}
}
}
Models:
namespace ReservationManagement.SignalRInterface.Model
{
public class TestModel
{
public string Name { get; set; }
public override string ToString()
{
return Name;
}
}
}
namespace ReservationManagement.SignalRInterface.Model
{
public class LocationModel
{
public string Name { get; set; }
public override string ToString()
{
return Name;
}
}
}
ViewModel:
using Microsoft.AspNetCore.SignalR.Client;
using Prism.Commands;
using ReservationManagement.SignalRInterface.Model;
namespace ReservationManagement.UnoPrism.ViewModels
{
class TestViewModel: ViewModelBase
{
private HubConnection HubConnection { get; set; }
public DelegateCommand Loaded { get; private set; }
public LocationModel LocationModel
{
get => _locationModel;
set { SetProperty(ref _locationModel, value); }
}
private LocationModel _locationModel;
public TestModel TestModel
{
get => _testModel;
set { SetProperty(ref _testModel, value); }
}
private TestModel _testModel;
public TestViewModel()
{
Loaded = new DelegateCommand(LoadedExecute);
}
private async void LoadedExecute()
{
HubConnection = new HubConnectionBuilder()
.WithUrl("http://localhost:5000/TestServiceHubAnyOrigin")
.WithAutomaticReconnect()
.Build();
await HubConnection.StartAsync();
LocationModel = await HubConnection.InvokeAsync<LocationModel>("LocationModel");
TestModel = await HubConnection.InvokeAsync<TestModel>("TestModel");
}
}
}
The call for LocationModel works fine and it is set to what the service returns. The call for TestModel results in an exception. If i switch the calling order (1. TestModel, 2. LocationModel) the exception will still be thrown on the TestModel-call.
Everything works perfectly fine when i build for Uwp.
Exception:
System.NotSupportedException: Deserialization of types without a parameterless constructor, a singular parameterized constructor, or a parameterized constructor annotated with 'JsonConstructorAttribute' is not supported. Type 'ReservationManagement.SignalRInterface.Model.TestModel'. Path: $ | LineNumber: 0 | BytePositionInLine: 1. ---> System.NotSupportedException: Deserialization of types without a parameterless constructor, a singular parameterized constructor, or a parameterized constructor annotated with 'JsonConstructorAttribute' is not supported. Type 'ReservationManagement.SignalRInterface.Model.TestModel'.
I also tried this, as the exception suggests, with a singular parameterized constructor and a parameterized constructor annotated with 'JsonConstructorAttribute', but still the same exception.
This is a generic issue related to the IL Linker step, which removes members that are detected as not used, in some cases incorrectly when reflection is used.
You will need to add linker descriptors to fix this in the LinkerConfig.xml file in the WebAssembly project, likely in the assembly that contains the ReservationManagement namespace.
You can find additional documentation about the linker configuration here.

How to make ASP.NET to stop interpret null as string

I have a Web API method:
public List<Task> GetTasks([FromUri] TaskFilter filter)
{
}
The method has parameter with list of nullable identifiers:
public class TaskFilter
{
public IList<int?> Assignees { get; set; }
}
When I call it:
GET /tasks?assignees=null
Server returns an error:
{
"message":"The request is invalid.",
"modelState": {
"assignees": [ "The value 'null' is not valid for Nullable`1." ]
}
}
It works only if I pass empty string:
GET /tasks?assignees=
But standard query string converters (from JQuery, Angular, etc) do not work with nulls in such way.
How to make ASP.NET to interpret 'null' as null?
Upd: The query string can contain several identifiers, e.g.:
GET /tasks?assignees=1&assignees=2&assignees=null
Upd2: JQuery converts nulls in array to empty strings, and ASP.NET interprets them as null. So the question is about calling WebAPI from Angular 1.6 ($HttpParamSerializerProvider)
Upd3: I know about workarounds, but I do not ask for them. I want a solution for specific problem:
It is a GET method
Method accepts a list from Uri
A list can contain null values
It should be List<int?> because API docs are generated automatically, and I do not want to see text array as parameter type
By default ASP.NET expects empty strings for null values (JQuery.param works in that way)
But some client libraries (e.g. Angular) does not convert null array items to empty strings
You can create a custom model bind for this specific type, inherithing from DefaultModelBinder, for sample:
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
public class TaskFilterBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, System.Web.Mvc.ModelBindingContext bindingContext)
{
var request = controllerContext.HttpContext.Request;
var assignees = request.QueryString["assignees"];
if (assignees == "null") // check if assignees is null (string) then return NULL
return null;
return assignees;
}
}
Finally we need to inform the controller as to the binding we want it to use. This we can specify using attributes
[ModelBinder(typeof(TaskFilterBinder))]
as below:
public List<Task> GetTasks([FromUri(ModelBinder=typeof(TaskFilterBinder))] TaskFilter filter)
{
// Do your stuff.
}
For more reference check this link on Custom Model Binders.
Hope, this solves your problem . Thanks
Finally, I found a solution using custom value provider:
using System;
using System.Collections.Generic;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.ValueProviders;
using System.Web.Http.ValueProviders.Providers;
using System.Globalization;
using System.Net.Http;
using System.Web.Http.ModelBinding;
public sealed class NullableValueProviderAttribute : ModelBinderAttribute
{
private readonly string[] _nullableColumns;
public NullableValueProviderAttribute(params string[] nullableColumns)
{
_nullableColumns = nullableColumns;
}
public override IEnumerable<ValueProviderFactory> GetValueProviderFactories(HttpConfiguration configuration)
{
return new ValueProviderFactory[] { new NullableValueProviderFactory(_nullableColumns) };
}
}
public class NullableValueProviderFactory : ValueProviderFactory, IUriValueProviderFactory
{
private readonly string[] _nullableColumns;
public NullableValueProviderFactory(string[] nullableColumns)
{
_nullableColumns = nullableColumns;
}
public override IValueProvider GetValueProvider(HttpActionContext actionContext)
{
return new NullableQueryStringValueProvider(actionContext, CultureInfo.InvariantCulture, _nullableColumns);
}
}
public class NullableQueryStringValueProvider : NameValuePairsValueProvider
{
private static readonly string[] _nullValues = new string[] { "null", "undefined" };
private static IEnumerable<KeyValuePair<string, string>> GetQueryNameValuePairs(HttpRequestMessage request, string[] nullableColumns)
{
foreach (var pair in request.GetQueryNameValuePairs())
{
var isNull = Array.IndexOf(nullableColumns, pair.Key) >= 0 && Array.IndexOf(_nullValues, pair.Value) >= 0;
yield return isNull ? new KeyValuePair<string, string>(pair.Key, "") : pair;
};
}
public NullableQueryStringValueProvider(HttpActionContext actionContext, CultureInfo culture, string[] nullableColumns) :
base(GetQueryNameValuePairs(actionContext.ControllerContext.Request, nullableColumns), culture)
{ }
}
And specify it in Web API action:
public List<Task> GetTasks([NullableValueProvider("assignees")] TaskFilter filter)
{
}

ASP.NET MVC4: IQueryable does not contain a definition for 'Add'

I have tried to make an MVC news system. I started by the use a pluralsight tutorial which was used to create a department with employees. I changed the idea to fit my own purposes, changing the departments to "category" and employees to "newspost". This all works out fine, but now I want to remove the categories, since I don't need categories for my news system. But I can't add to the database using entityframework when I do this.
I have an interface for the datasource that looks like this:
INewMvcSiteDataSource
public interface INewMvcSiteDataSource
{
IQueryable<NewsPost> NewsPosts { get; }
void Save();
}
This is inherited by my DB Context class:
NewMvcSiteDb
public class NewsMvcSiteDb : DbContext, INewMvcSiteDataSource
{
public NewsMvcSiteDb() : base("DefaultConnection")
{
}
public DbSet<NewsPost> NewsPosts { get; set; }
IQueryable<NewsPost> INewMvcSiteDataSource.NewsPosts
{
get { return NewsPosts; }
}
public void Save()
{
SaveChanges();
}
}
I then want to use it in the controller to add a newspost to the database:
NewsController
var newsPost = new NewsPost()
{
Subject = newsModel.Subject,
Content = newsModel.Content,
ImagePath = newsModel.ImagePath
};
_db.NewsPosts.Add(newsPost);
_db.Save();
But this is where the ADD fails with the message: 'System.Linq.IQueryable' does not contain a definition for 'Add' and no extension method 'Add' accepting a first argument of type 'System.Linq.IQueryable' could be found (are you missing a using directive or an assembly reference?)
Now as the error says, its caused by using IQueryable, but I have no idea how else to do it.
Can you guys help?
Thanks.
If you don't mind exposing DbSet via your interface (some people don't like the ORM bleeding into the application),you should be able to do the following:
public interface INewMvcSiteDataSource
{
DbSet<NewsPost> NewsPosts { get; }
void Save();
}
public class NewsMvcSiteDb : DbContext, INewMvcSiteDataSource
{
public NewsMvcSiteDb() : base("DefaultConnection")
{
}
public DbSet<NewsPost> NewsPosts { get; set; }
public void Save()
{
SaveChanges();
}
}

Error sending object to .net signalr client

My understanding is that with signalr I can just send objects back and forth. I am trying to set up a .net client to receive notifications that orders have been placed on a web site. I am trying to set up a very simple example so that I understand the concepts. It works great when I am sending a string notification back to the client, but when I try to send an object I get an error:
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException was unhandled by user code
HResult=-2146233088
Message=The best overloaded method match for 'ConsoleHub.Program.DisplayOrder(ConsoleHub.Order)' has some invalid arguments
Source=Anonymously Hosted DynamicMethods Assembly
StackTrace:
at CallSite.Target(Closure , CallSite , Type , Object )
at System.Dynamic.UpdateDelegates.UpdateAndExecuteVoid2[T0,T1](CallSite site, T0 arg0, T1 arg1)
at ConsoleHub.Program.<Main>b__6(Object o) in c:\Working\OrderNotifier\ConsoleHub\Program.cs:line 23
at Microsoft.AspNet.SignalR.Client.Hubs.HubProxyExtensions.<>c__DisplayClass6`1.<On>b__4(JToken[] args)
at Microsoft.AspNet.SignalR.Client.Hubs.Subscription.OnData(JToken[] data)
at Microsoft.AspNet.SignalR.Client.Hubs.HubProxy.InvokeEvent(String eventName, JToken[] args)
at Microsoft.AspNet.SignalR.Client.Hubs.HubConnection.OnReceived(JToken message)
at Microsoft.AspNet.SignalR.Client.Connection.Microsoft.AspNet.SignalR.Client.IConnection.OnReceived(JToken message)
at Microsoft.AspNet.SignalR.Client.Transports.HttpBasedTransport.ProcessResponse(IConnection connection, String response, Boolean& timedOut, Boolean& disconnected)
InnerException:
My class:
public class Order
{
public int OrderId { get; set; }
public string Name { get; set; }
public string OrderItem { get; set; }
}
My hub:
using Microsoft.AspNet.SignalR.Hubs;
using OrderNotifier.Models;
using System.Linq;
using System.Threading.Tasks;
namespace OrderNotifier.Hubs
{
public class NotifierHub : Hub
{
OrderContext db = new OrderContext();
public void Hello()
{
Clients.Caller.Welcome("hello");
}
}
}
My controller action:
[HttpPost]
public ActionResult Create(Order order)
{
if (ModelState.IsValid)
{
db.Orders.Add(order);
db.SaveChanges();
SendNotifier.SendOrderNotification(String.Format("{0} ordered {1}", order.Name, order.OrderItem), order);
return RedirectToAction("Index");
}
return View(order);
}
SendNotifier - which is a little weird because I am having it send both a string version and an object version for testing:
public class SendNotifier
{
public static void SendOrderNotification(string message, Order order)
{
var context = GlobalHost.ConnectionManager.GetHubContext<NotifierHub>();
context.Clients.All.Notify(message);
context.Clients.All.Order(order);
}
}
And my console application:
using Microsoft.AspNet.SignalR.Client.Hubs;
using OrderNotifier.Models;
using System;
namespace ConsoleHub
{
class Program
{
static void Main(string[] args)
{
var hubConnection = new HubConnection("http://localhost:60692");
var order = hubConnection.CreateHubProxy("NotifierHub");
//
// Set up action handlers
//
order.On("Welcome", message => Console.WriteLine(message));
order.On("Notify", message => Console.WriteLine(message));
order.On("Order", o => DisplayOrder(o));
hubConnection.Start().Wait();
order.Invoke("Hello").Wait();
Console.WriteLine("Initialized...");
Console.ReadLine();
}
public void DisplayOrder(Order o)
{
Console.WriteLine(String.Format("Order object received.../r/nOrderId: {0}/r/nName: {1}/r/nOrderItem: {2}", o.OrderId, o.Name, o.OrderItem));
//Console.WriteLine(o);
}
}
}
If I change the DisplayOrder parameter to be a string it works. I know I could probably manually deserialize it using Json.Net, but my understanding is that I should just be able to work with it as an object and let signalr deserialize. What am I missing?
You're using the dynamic object overload of On. You need to specify the type:
order.On<Order>("Order", DisplayOrder);

Resources