ASP .Net Core - Inheriting from RazorPage<TModel> issue - asp.net-core

I'm trying to define a base page by inheriting from RazorPage. If I pass anything other than TModel in my #inherit section of the page, I get the following error:
ArgumentException: Property 'ViewData' is of type 'Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary`1[[MyProject.Models.IndexViewModel, MyProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]', but this method requires a value of type 'Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary`1[[System.Object, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]'.
Parameter name: viewContext
How can I override ViewData so I can pass my custom model instead of IndexViewModel in the following line:
#inherits MyProject.Base.BaseView
Thanks

So I have done this to get around this issue, no idea whether it is a good or bad approach but is working
instead of actually using TModel in the RazorPage, use object for the generic type in RazorPage (RazorPage) and create a property to expose your own Model of the type you requested and cast Model to that type.
like this:
public abstract class MenuViewPage<TModel> : RazorPage<object>
{
public TModel PageModel {
get
{
return (TModel)ViewData.Model;
}
}
}

Related

SerializationException when returning custom classes from a WCF service

I have the following classes...
public abstract class Fallible<T> {
}
public class Success<T> : Fallible<T> {
public Success(T value) {
Value = value;
}
public T Value { get; private set; }
}
The background to this can be found in a previous question of mine, but you don't need to read that post as the classes above are all that's needed to see the problem.
If I have a simplified WCF service call like this...
[OperationContract]
public Fallible<Patient> GetPatient(int id) {
return new Success<Patient>(new Patient {ID = 1,FirstName = "Jim",Surname = "Spriggs"});
}
...then when I try to call the service from the WPF app that consumes it (or the WCF test client), I get a CommunicationException exception...
There was an error while trying to serialize parameter :GetPatientResult. The
InnerException message was 'Type 'PhysioDiary.Entities.FallibleClasses.Success`1[[PhysioDiary.Entities.Patient,
PhysioDiary.Entities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]'
with data contract name > 'SuccessOfPatient0yGilFAm:http://schemas.datacontract.org/2004/07/PhysioDiary.Entities.FallibleClasses'
is not expected. Consider using a DataContractResolver if you are using
DataContractSerializer or add any types not known statically to the list of
known types - for example, by using the KnownTypeAttribute attribute or by
adding them to the list of known types passed to the serializer.'. Please
see InnerException for more details.
...with an inner SerializationException exception of...
Type 'PhysioDiary.Entities.FallibleClasses.Success`1[[PhysioDiary.Entities.Patient,
PhysioDiary.Entities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]'
with data contract name > 'SuccessOfPatient0yGilFAm:http://schemas.datacontract.org/2004/07/PhysioDiary.Entities.FallibleClasses'
is not expected. Consider using a DataContractResolver if you are using
DataContractSerializer or add any types not known statically to the list
of known types - for example, by using the KnownTypeAttribute attribute
or by adding them to the list of known types passed to the serializer.
I've tried adding [DataContract] to the class and [DataMember] to each property, as well as adding a [KnownType] attribute for all four classes involved, and adding a [ServiceKnownType] for each of them on the service contract, but nothing helps.
I've read countless answers to the same question, but have not found anything that works. My services return other custom classes, and they all get serialised without a problem.
Anyone able to explain what the problem is here? Please let me know if I've not supplied enough information.
Turns out all I needed to do was decorate the service method with [ServiceKnownType] attributes for the base type, and each derived type...
[OperationContract]
[ServiceKnownType(typeof(Fallible<Patient>)]
[ServiceKnownType(typeof(Success<Patient>)]
[ServiceKnownType(typeof(BadIdea<Patient>)]
[ServiceKnownType(typeof(Failure<Patient>)]
public Fallible<Patient> GetPatient(int id) {
return new Success<Patient>(new Patient {ID = 1,FirstName = "Jim",Surname = "Spriggs"});
}
Although it's a pain to have to add four attributes to every call, it works. I'd like to know if there is a way to combine them into one attribute, but at least I have a working service now.
Hope this helps someone.

InvalidOperationException rendering ViewComponent in Strongly-Typed View

Recently updated dotnet core 1.0.1 to 1.1 and ViewComponent in MVC starts failing with the below exception:
InvalidOperationException: One or more errors occurred. (The model item passed into the ViewDataDictionary is of type 'App.Models.HomeViewModel', but this ViewDataDictionary instance requires a model item of type 'App.Components.LoginViewComponent'.)
The Index.cshtml renders LoginViewComponent:
#model App.Models.HomeViewModel
<html>
#Component.InvokeAsync("LoginViewComponent")
</html>
Views/Home/Index.cshtml
The ViewComponent LoginViewComponent/Default.cshtml is just a class that displays it's model's info:
#model App.Components.LoginViewCompoent
<body>
<div>#Html.DisplayFor(v=>v.LoginName)</div>
</body>
Views/Shared/Components/LoginViewComponent/Default.cshtml
It renders fine when the #model directives is removed from Default.cshtml.
Isn't ViewComponent suppose to be separated and agnostic from the parent view that is wrapping it? From the exception it seems that it would be require to declare the LoginViewComponent ViewComponent in HomeViewModel class in order to render it.
Couldn't find any change note on this on asp.net core github.
Comment and help on this would be greatly appreciated.
I've came across the same error, someone in my team updated Microsoft.AspNetCore.Mvc version from 1.0.0 to 1.1.0 and some of the components I had in Strongly-Type views started throwing
InvalidOperationException: The model item passed into the ViewDataDictionary is of type 'My.StronglyView.ObjectType', but this ViewDataDictionary instance requires a model item of type 'My.ViewComponent.ObjectType'.
I am not sure if this change was intentional, but it is definitely not what we would expect.
I haven't got the time to research about the reasons of this 'breaking' change but I came with a solution.
Thing is, if you pass a null object to your ViewComponent.View() method, we get this exception. Any non-null object passed through it, would update the ViewData.ModelExplorer and the correct object-type would have been registered, avoiding this exception.
Using Tester-Doer pattern, same pattern used in some classes of .Net Framework, We can now pass a non-null object to the ViewComponent and use it and its wrapped object as We need.
What I did was, I created a interface IViewComponentModel<T> as class ViewComponentModel<T> as below:
// Interface for ViewComponentModel
public interface IViewComponentModel<T>
where T : class
{
T Data { get; }
bool HasData();
}
// ViewComponentModel class for the Strongly-Type View Component
public class ViewComponentModel<T> : IViewComponentModel<T>
where T : class
{
public T Data { get; private set; }
public ViewComponentModel(T data)
{
Data = data;
}
public bool HasData() => Data != null;
}
In my ViewComponent class implementation, I return View(new ViewComponentModel<AnyReferenceType>(myModel));
public async Task<IViewComponentResult> InvokeAsync()
{
var myViewData = _myService.GetSomeObjectForMyViewComponent();
var model = new ViewComponentModel<MyViewDataType>(myViewData);
return await Task.FromResult(View(model));
}
And finally, in my Component View (.cshtml) I have the code below:
#addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
#model ViewComponentModel<MyViewDataType>
Now you can do whatever you want with this object inside of the view and to use your real model, just call #Model.Data and voilĂ .
In this way, We will never pass a null object to the ViewComponent and it won't 'inherit' the object type from the View.
Hopefully it helps!
asp.net-core asp.net-core-mvc dotnet-core asp.net-core-1.1
Simple solution is that, in ViewComponent class check null for view model, and if view model is null, then return empty Content result as following:
public async Task<IViewComponentResult> InvokeAsync()
{
var vm = some query for ViewModel;
if(vm != null)
{
return View(vm);
}
return Content("");
}
By default it will try to pass in the model of the "Parent View" ,not sure what you would call that, try updating your code like this
#Component.InvokeAsync("LoginViewComponent", new App.Components.LoginViewComponent())
so that partial view can have what it needs, in order to serve up it's content.

WCF Update Service Reference Error

I'm desesperated, I'm trying to update an existing service reference to a WCF service (sharing types) and I can't. I've tryied all what I've found on Google (social.msdn, stackoverflow, ...) but I haven't found the solution to my problem.
I've have a ServiceContract and I add a new Operation like the code below:
[ServiceContract]
public partial interface IServiceDTO : IGenericServiceDTO<EntityDTO>
{
// Some OperationContracts working like
[OperationContract]
EntityDTO[] Method(int field);
// NewMethod
[OperationContract]
OtherEntityDTO[] NewMethod(int field);
}
[DataContract]
public class EntityDTO {
// Some properties working
}
[DataContract]
public class OtherEntityDTO {
// Some properties working
[DataMember]
YetAnotherEntity NewProperty {get;set;}
}
When I try to update the service reference it throws me the follwing error:
Attempting to download metadata from 'http://localhost:65499/Services/Acciones/ProcesoServiceDTO.svc' using WS-Metadata Exchange or DISCO.
Error: Cannot import wsdl:portType
Detail: An exception was thrown while running a WSDL import extension: System.ServiceModel.Description.DataContractSerializerMessageContractImporter
Error: Referenced type 'mpm.seg.ServiceModel.DTO.DataContracts.Acciones.ProcesoDTO, mpm.seg.ServiceModel.DTO.DataContracts, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' with data contract name 'ProcesoDTO' in namespace 'http://schemas.datacontract.org/2004/07/mpm.seg.ServiceModel.DTO.DataContracts.Acciones' cannot be used since it does not match imported DataContract.
Need to exclude this type from referenced types.XPath to Error Source: //wsdl:definitions[#targetNamespace='http://tempuri.org/']/wsdl:portType[#name='IProcesoServiceDTO']
First of all, I don't understand exactly the sentence "...cannot be used since it does not match imported DataContract." How the svcutil is trying to match referenced type to imported DataContract? I've referenced the project that have the referenced types on the client project, cause server and client are in the same solution, but I've tried to separate them and reference exactly the same dll too.
Also, when I try, for example, the following situation it works (write "NewProperty" of the "OtherEntityDTO to EntityDTO"), and I don't understand the difference:
[ServiceContract]
public partial interface IServiceDTO : IGenericServiceDTO<EntityDTO>
{
// Some OperationContracts working like
[OperationContract]
EntityDTO[] Method(int field);
// NewMethod
[OperationContract]
OtherEntityDTO[] NewMethod(int field);
}
[DataContract]
public class EntityDTO {
// Some properties working
[DataMember]
YetAnotherEntity NewProperty {get;set;}
}
[DataContract]
public class OtherEntityDTO {
// Some properties working
}
Please, help me and thanks a lot in advance.
Sorry, but after I've posted the question I've found the problem and it was a reported bug (http://blogs.msdn.com/b/distributedservices/archive/2010/02/04/wcf-client-issue-with-reuse-types-from-referenced-assemblies.aspx?wa=wsignin1.0). Another developer had added this attribute (IsReference=true) on a parent class and I didn't know. Now I must to workaround this bug, but that's another battle.
Anyway, I don't understand why sometimes work and sometimes not...
Thanks.
I had a similar error, but my issue seemed to be different.
I had a readonly property and I kept getting that error. When I changed it to a normal property and added a set (that did nothing), the contract worked fine.

wcf netdatacontractserializer exception serialising idictionary with enumeration as key

I am using the NetDataContractSerialiser with WCF. This is working well with all our types being serialised. However, a service I am calling is generating the following exception
The formatter threw an exception while trying to deserialize the message:
There was an error while trying to deserialize parameter http://tempuri.org/:xmlServiceObjIN. The InnerException message was 'The deserializer cannot load the type to deserialize because type 'System.Collections.Generic.EnumEqualityComparer`1[[GrantEd.Common.DomainModel.Code.Enums.enumFundingParameterContextKey, GrantEd.Common.DomainModel.Code, Version=14.0.71.0, Culture=neutral, PublicKeyToken=null]]' could not be found in assembly 'mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.
Check that the type being serialized has the same contract as the type being deserialized and the same assembly is used.'. Please see InnerException for more details.
The class being serialised has a property defined as
public IDictionary<enumFundingParameterContextKey, string> Context { get; set; }
the declaration of the enum is
[Serializable]
public enum enumFundingParameterContextKey
{
[EnumMemberAttribute()]
ClientId = 0,
[EnumMemberAttribute()]
EntitlementDefinitionId = 1
}
which is defined in another assmebly.
When I replace the enumeration with int the class deserialises with no problems. Any ideas why using the enum would result the exception?
The reason for using NetDataContractSerializer was to for type information to be available and avoid having to use KnownType
Make the base type as non integer for your enum. e.g. a byte.
Example:
[Serializable] public enum enumFundingParameterContextKey : byte
{
[EnumMemberAttribute()]
ClientId = 0,
[EnumMemberAttribute()]
EntitlementDefinitionId = 1
}
Details are in my following blog post: dotnet-35-to-dotnet-40-enum
Try to mark enum with [DataContract] instead of [Serializable]. But it looks like the enum type is unknown at all on the client.

WCF and interfaces

I need to have 2 families of classes (one on server and one on client side) which are identical in data structure but differs in behavior. Also I suppose that these fmailies will be enough big, thus I don't want to implement intermediate level of DTO and transformations into and from it.
I decided to move in following manner: declare shared assembly with declaration of data and services interfaces like these ones:
public interface ITest
{
string Title { get; set; }
int Value { get; set; }
}
public interface IService
{
ITest GetData();
}
Having these declarations I can implement these interfaces on server side for example basing on Entity Framework (data) and WCF (services). On the client side I can use for example Dependency Properties (data) and WCF (service).
When I started trying to implement this, I met several troubes.
First one was about server side of WCF - it simply do not want to work with interfaces as return parameters. Thanks to StackOverflow this issue was resolved like here
.
Next problem is that XML rendered by server side includes qulified assembly name of serialized on the server class.
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<GetDataResponse xmlns="http://tempuri.org/">
<Test z:Id="1" z:Type="Dist.Server.Model.Test" z:Assembly="Dist.Server, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" xmlns="http://schemas.datacontract.org/2004/07/Dist.Server.Model" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
<Title z:Id="2">Test</Title>
<Value>123</Value>
</Test>
</GetDataResponse>
</s:Body>
</s:Envelope>
Thus during deserialization on client side there was an attempt to load this type. As this type is inaccessible on client side, I had to implement some kind of type mapping. I found that this is quite easy as NetDataContractSerializer used for serialization supports Binder property. Thus I override this property on client side and return correct value (hardcode in meantime, but it's OK for tests).
public class NetBinder : SerializationBinder
{
public override Type BindToType(string assemblyName, string typeName) {
var type = Type.GetType("Client.Test, Client, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null");
return type;
}
}
Now I have following picture:
- Server uses NetDataContractSerializer to serialize response. It uses actual value (calss) during serialization instead of type used in declaration of service (interface).
- Client side receives XML and starts deserialization. To resolve type, NetDataContractSerializer calls my Binder that returns correct type.
- NetDataContractSerializer creates instance of correct type and starts loading of its properties.
And here I got a trouble that I don't know how to resolve. Values of properties are not deserialized. It means that instance of class is created correctly (uninitialized instance created through reflection services), but all properties are in their default values (0 or null).
I tried to play with declaration of class on client side: mark it as [Serializable], implement ISerializable, etc., but nohing is helpful. NetDataContractSerializer requires class to be marked as [DataContract] or [Serializable]. First option leaves properties empty, second one causes exceptions like "</Test> is unexpected, expected is bla-bla-bla_Value_Ending_bla-bla-bla".
Does anybody have any suggestions on how to resolve this last step?
I can provide full sources for better understanding, but I don't know ifI can attach them here...
Thanks in advance.
You could have a look at frameworks like AutoMapper that would take care the transformation to and from DTO. This would make your life much easier.
Instead of using an interface why not create a base class containing only the data and inherit it on both sides by sharing the assembly containing this class. Playing around with the ServiceKnownType should help you fix the last issues.
You may also share the same base classes on both sides and implement the specific logic as extension methods.
Seems that problem was solved enough easily. I created own serializer and used it instead of NetDataContractSerializer. Code is quite simple:
public class MySerializer: XmlObjectSerializer
{
public override void WriteStartObject(XmlDictionaryWriter writer, object graph) {
}
public override void WriteObjectContent(XmlDictionaryWriter writer, object graph) {
var formatter = new XmlSerializer(graph.GetType());
formatter.Serialize(writer, graph);
}
public override void WriteEndObject(XmlDictionaryWriter writer) {
}
public override object ReadObject(XmlDictionaryReader reader, bool verifyObjectName) {
var realType = Type.GetType("Client.Test, Client, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"); //temporary solution
var formatter = new XmlSerializer(realType);
return formatter.Deserialize(reader);
}
public override bool IsStartObject(XmlDictionaryReader reader) {
return true;//temporary solution
}
}
I checked SOAP that goes from server to client and it's almost the same as NetDataSerializer renders. The only difference is in attribute xmlns="".
Kai, Johann thanksfor your tries.