首页 新闻 会员 周边

这样共享Session到Service层可行吗?

0
悬赏园豆:20 [已解决问题] 解决于 2018-01-23 16:02

在显示层用如下代码,把需要存储的值放到线程拥有者里,代码如下

         var claimsPrincipal = Thread.CurrentPrincipal as ClaimsPrincipal;
             var a =new  ClaimsIdentity();
             a.AddClaim(new Claim("UserId","150"));
            if (claimsPrincipal != null) claimsPrincipal.AddIdentity(a);

在Service层调用的时候如下:

  var claimsPrincipal = Thread.CurrentPrincipal as ClaimsPrincipal;
            var userId= claimsPrincipal.Claims.FirstOrDefault(c => c.Type == "UserId").Value;

请问这样把Seesion共享到Service可行吗?

loveseejoy的主页 loveseejoy | 初学一级 | 园豆:177
提问于:2018-01-22 15:44
< >
分享
最佳答案
1

不建议通过这种方式隐式的传递信息,这样通用性相当差而且由于缺少足够提示对后期维护也是相当麻烦。

建议这种是直接在交互的方法上显式暴露出来进行传递,这样你做单元测试的话也会简单很多

收获园豆:20
Daniel Cai | 专家六级 |园豆:10424 | 2018-01-22 18:49

我后面会对这个进行封装的,类似abp那种的 AbpSession.XXX

loveseejoy | 园豆:177 (初学一级) | 2018-01-22 21:39

@loveseejoy: 不建议这样,你这样换汤不换药,接口方法应该清晰,依赖什么参数应该通过方法签名暴露,任何隐含的需求信息都是隐患。

Daniel Cai | 园豆:10424 (专家六级) | 2018-01-22 22:00

@Daniel Cai: 那请问如何把Session共享到Service层,比如我在Service要知道当前的登录用户的先关信息

loveseejoy | 园豆:177 (初学一级) | 2018-01-23 09:51

@loveseejoy: 为什么非要想着把这信息“共享”呢?你直接在service的接口方法上暴露出来不就可以了么?

比如

string GetUserId(Principal principal....)

如果觉得不方便,很多地方都需要写一大噼里啪啦才能提供出相关参数那么可以把方法变下

string GetUserId(Func<Principal> getPrincipal.....)

同时通过简单的构建一个帮助类,在帮助类中返回这个func(内部实现及你的从session中获取)

做的再好点的话你可以继续提炼出一个IPrincipalProvider

interface IPrincipalProvider

{

  Principal GetCurrentPrincipal();

}

基于你session的方式实现这个接口,在service的class的构造函数或者你觉得合适的方式将IPrincipalProvider注入进去

类似(伪代码)

class MyService:IXXXService

{

  IPrincipalProvider _provider;

  public MyService(IPrincipalProvider provider){_provider=provider;}

  

  public string GetUserId()

  {

    return provider.GetCurrentPrincipal().Get....

  }

}

 

//启动注册或配置注册

IOCContainer.Register<IPrincipalProvider,SessionPrincipalProvider>(....);

 

//执行时获取

IXXXService service=IOCContainer.Resolve<IXXXService>();

service.GetUserId();

Daniel Cai | 园豆:10424 (专家六级) | 2018-01-23 10:36

@Daniel Cai: 

大神,谢谢你码了这么多字,这段ioc注入的代码我看懂了。

但是我想问的是GetUserId方法的实现,用我上面那种方式可行吗?

场景是:我们在web层登录后,把用户信息存到session了,在controller中可以用session,但是到service层并没有session可用,比如service中我们要进行审计日志记录,那怎么拿到web层中的Session中的userid呢?不可能在每个service方法的入参中定义一个userid,然后在action一个个赋值吗?或者在过滤器中统一赋值操作,但我始终觉得这不是一个好方法。我看了abp源码,他们用的类似我问题中贴的那段代码,但是他们是基于owin的,我这里不像用那么多,只想实现个简单的。

loveseejoy | 园豆:177 (初学一级) | 2018-01-23 14:15

@loveseejoy: 这里是因为你实际使用的是Thread.CurrentPrincipal,和session不是一个东西,而估计应该是在前置逻辑中根据session信息初始化了这块(对站点框架完全无研究),如果只是从这块来看你往后传递是没问题。

但我提到的重点是接口方法应该清晰,有显示的东西告知我需要啥(当然如果有隐含的也算,比如类似包含Current字眼的,这种会让调用方知道这里需要某些上下文的东西传递后才满足Current语义),你不能防止别人错误的使用你无参的GetUserId方法,但如果有我前面所说的任意一种方式都会显式的告知使用你方法的人这里我需要一些凭据信息,如果你连这些信息都给不了我那就连编译都过不了。

的确使用我提及的各种方式会增加很多重复的代码,但如果使用合理的技术去进行化解(比如iioc的启动一次性注册)是可以完全避免这种问题

Daniel Cai | 园豆:10424 (专家六级) | 2018-01-23 15:45

@Daniel Cai:

恩是的,我是在前置逻辑中把需要的东西从session中取出放到Thread.CurrentPrincipal中。

非常感谢你提的接口意见,说的很有道理。谢谢。

loveseejoy | 园豆:177 (初学一级) | 2018-01-23 16:02
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册