ArticleThe name is so difficult. I want to clearly express the purpose of this article, and I want to be short and concise.
Why is it "in person? What I want to express is:ProgramWe have control over everything. This is called in person. Speaking of this word, there is also an story (if it is the same, it is a coincidence ):
When I was in high school 3, I had a classmate surnamed Huang and named ** in class 4. He was in the middle school and later transferred to the middle school. This classmate surnamed Huang has been pursuing a kind of realm. What kind of realm is it difficult to describe... he can discharge the exhaust gas in class without any scrubs, make a sneeze that can be heard in other rooms within 30 m without warning, or even joke with the principal, once, he was not allowed to allow students to go to the teachers' WC during the recess, but he did not follow this rule. He first arrived and the principal came in when he was releasing water, then he said hello to the principal: "Master, have you come to the bathroom yourself? ", When the headmaster was stunned, he had to say "Well, well...
I miss the time on campus.
Enter the subject:
Why do I need to be "personally"? It must be explained that my intention is to build a restful service, write an atom client, and use webrequest to submit data to the server. Of course, the format is atom10. on the server side, use the request to extract the data uploaded by the client.CodeAs shown in:
Public actionresult create () {var entry = getfromrequest ();//...}
Is that all right? I thought it was good when I first wrote it, but I thought it was bad at the second glance. Why? If this entry comes from the parameters of the create method, it would be nice, I think of a problem I encountered when I was learning WCF. I can use the atom10feedformatter class to obtain the entry instance in the parameter. Why? The Code becomes like this:
Public actionresult create (atom10feedformatter <logentry> log ){//...}
Unfortunately, based on previous experience, in this method, you can use log. item to obtain the entity from the client, but here we find that log. item is null.
Only then can we find that the original MVC and WCF syndication mechanisms are different.
By reading the MVCSource codeIt is found that the getparametervalues method in controlleractioninvoker obtains the parameter list of the action and generates the corresponding parameter values according to some policies, however, this getparametervalues seems to be able to achieve what I want only through overloading. How can I ensure that the original intention of MVC is not affected? Try not to overload it first. check whether there is a lightweight solution.
Again, in MVC, isn't the filter almost omnipotent? It's better to get an actionfitler, So we define a type:
[Attributeusage (attributes. Method)] public class attributes: attribute, iactionfilter {public void onactionexecuting (actionexecutingcontext filtercontext) {//...} public void onactionexecuted (actionexecutedcontext filtercontext ){}}
I tried to read data from the request in onactionexecuting, and found a problem quickly. All actions were executed. The methods of this feature class were not executed yet. Check the MVC source code carefully, the problem is found:
Protected virtual actionexecutedcontext parameters (controllercontext, ilist <iactionfilter> filters, actiondescriptor, idictionary <string, Object> parameters) {controllercontext = new parameters (controllercontext, parameters, parameters ); func <actionexecutedcontext> continuation = () => New actionexecutedcontext (controllercontext, actiondescriptor, false/* canceled */, null/* exception */) {result = invokeactionmethod (controllercontext, actiondescriptor, parameters)}; // need to reverse the Filter list because the continuations are built up backward func <actionexecutedcontext> thunk = filters. reverse (). aggregate (continuation, (next, filter) => () => invokeactionmethodfilter (filter, precontext, next); Return thunk ();}
The call of action was before actionmethodfitler... Khan. It was really not a long memory. The last time I was cheated here, I forgot about it.
Return to the getparametervalues method...
(This saves two hours of thinking and trying)
One conclusion is that to implement Lightweight "non-intrusive" operations, M $ usually uses attribute or reflection. It seems inappropriate to use reflection here, attribute should be applied to the entry type or parameter itself. According to the naming conventions of M $, names such as custom, convert, and parameter should be used, with this idea, we found a type of custommodelbinderattribute.
Just for this type of name, I feel like I am doing this thing,Custom model binding feature, It looks like, there is a public method in this type:
Public abstract imodelbinder getbinder ();
When reading the MVC source code, I found that this imodelbinder interface is mostly used in the getparametervalues method. Let's look at the definition of imodelbinder:
Object bindmodel (controllercontext, modelbindingcontext bindingcontext );
The definition is like generating a parameter value from controllercontext and bindingcontext.
Directly create a subclass of custommodelbinderattribute:
[Attributeusage (attributetargets. parameter)] public class atomentryparameterconvertattribute: custommodelbinderattribute {public type entrytype {Get; private set;} public atomentryparameterconvertattribute (type entrytype): Base () {This. entrytype = entrytype;} public override imodelbinder getbinder () {return New atomentryconvertmodelbinder (this. entrytype );}}
Create an imodelbinder implementation:
Internal class atomentryconvertmodelbinder: imodelbinder {public type entrytype {Get; private set;} internal atomentryconvertmodelbinder (type entrytype) {This. entrytype = entrytype;} public object bindmodel (controllercontext, modelbindingcontext bindingcontext) {var result = atomservicehelper. getdatafromentry (controllercontext. httpcontext. request, this. entrytype, bindingcontext. modeltype); return result ;}}
Here I want to explain a little. In fact, what I received in the Action parameter is not a subclass of the syndicationitem type uploaded directly from the client atomentry, atomentry is only the atom-based data structure for client-server interaction. It is derived from the syndicationitem class and actually uses the entity class on the server. In my example:
Public class log {}
The log type is the entity type used by the real service and data layers.
Public class logentry: atomentry {} public class atomentry: syndicationitem {}
The logentry type is the data format in which the client interacts with the server.
Therefore, I not only need to upload the logentry instance to the server from the client, but also use parameters in the action on the server to directly obtain the Log Type instance, of course, the definition of log and logentry is a policy, or there is an agreement between them. If there is no agreement, neither of them can be converted. I like the Convention more than the configuration.
Atomservicehelper. getdatafromentry (controllercontext. httpcontext. request, this. entrytype, bindingcontext. modeltype)
The atomservicehelper class reads the data in the request, and then converts the entrytype instance to the parameter type instance.
In fact, I didn't check msdn for imodulebinder, but I just thought it was such a usage. No experiment has been done yet, so I wrote an example:
[Httppost] [serviceerror] public actionresult create ([atomentryparameterconvert (typeof (logentry)] logrecord log) {var logmng = new logmanager (); logmng. createlog (log); return New emptyresult ();}
Run, yeah! As expected, we got data from the client.